Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/bpf/bpftool/perf.c
26285 views
1
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2
// Copyright (C) 2018 Facebook
3
// Author: Yonghong Song <[email protected]>
4
5
#ifndef _GNU_SOURCE
6
#define _GNU_SOURCE
7
#endif
8
#include <ctype.h>
9
#include <errno.h>
10
#include <fcntl.h>
11
#include <stdlib.h>
12
#include <string.h>
13
#include <sys/stat.h>
14
#include <sys/types.h>
15
#include <unistd.h>
16
#include <dirent.h>
17
18
#include <bpf/bpf.h>
19
20
#include "main.h"
21
22
/* 0: undecided, 1: supported, 2: not supported */
23
static int perf_query_supported;
24
static bool has_perf_query_support(void)
25
{
26
__u64 probe_offset, probe_addr;
27
__u32 len, prog_id, fd_type;
28
char buf[256];
29
int fd;
30
31
if (perf_query_supported)
32
goto out;
33
34
fd = open("/", O_RDONLY);
35
if (fd < 0) {
36
p_err("perf_query_support: cannot open directory \"/\" (%s)",
37
strerror(errno));
38
goto out;
39
}
40
41
/* the following query will fail as no bpf attachment,
42
* the expected errno is ENOTSUPP
43
*/
44
errno = 0;
45
len = sizeof(buf);
46
bpf_task_fd_query(getpid(), fd, 0, buf, &len, &prog_id,
47
&fd_type, &probe_offset, &probe_addr);
48
49
if (errno == 524 /* ENOTSUPP */) {
50
perf_query_supported = 1;
51
goto close_fd;
52
}
53
54
perf_query_supported = 2;
55
p_err("perf_query_support: %s", strerror(errno));
56
fprintf(stderr,
57
"HINT: non root or kernel doesn't support TASK_FD_QUERY\n");
58
59
close_fd:
60
close(fd);
61
out:
62
return perf_query_supported == 1;
63
}
64
65
static void print_perf_json(int pid, int fd, __u32 prog_id, __u32 fd_type,
66
char *buf, __u64 probe_offset, __u64 probe_addr)
67
{
68
jsonw_start_object(json_wtr);
69
jsonw_int_field(json_wtr, "pid", pid);
70
jsonw_int_field(json_wtr, "fd", fd);
71
jsonw_uint_field(json_wtr, "prog_id", prog_id);
72
switch (fd_type) {
73
case BPF_FD_TYPE_RAW_TRACEPOINT:
74
jsonw_string_field(json_wtr, "fd_type", "raw_tracepoint");
75
jsonw_string_field(json_wtr, "tracepoint", buf);
76
break;
77
case BPF_FD_TYPE_TRACEPOINT:
78
jsonw_string_field(json_wtr, "fd_type", "tracepoint");
79
jsonw_string_field(json_wtr, "tracepoint", buf);
80
break;
81
case BPF_FD_TYPE_KPROBE:
82
jsonw_string_field(json_wtr, "fd_type", "kprobe");
83
if (buf[0] != '\0') {
84
jsonw_string_field(json_wtr, "func", buf);
85
jsonw_lluint_field(json_wtr, "offset", probe_offset);
86
} else {
87
jsonw_lluint_field(json_wtr, "addr", probe_addr);
88
}
89
break;
90
case BPF_FD_TYPE_KRETPROBE:
91
jsonw_string_field(json_wtr, "fd_type", "kretprobe");
92
if (buf[0] != '\0') {
93
jsonw_string_field(json_wtr, "func", buf);
94
jsonw_lluint_field(json_wtr, "offset", probe_offset);
95
} else {
96
jsonw_lluint_field(json_wtr, "addr", probe_addr);
97
}
98
break;
99
case BPF_FD_TYPE_UPROBE:
100
jsonw_string_field(json_wtr, "fd_type", "uprobe");
101
jsonw_string_field(json_wtr, "filename", buf);
102
jsonw_lluint_field(json_wtr, "offset", probe_offset);
103
break;
104
case BPF_FD_TYPE_URETPROBE:
105
jsonw_string_field(json_wtr, "fd_type", "uretprobe");
106
jsonw_string_field(json_wtr, "filename", buf);
107
jsonw_lluint_field(json_wtr, "offset", probe_offset);
108
break;
109
default:
110
break;
111
}
112
jsonw_end_object(json_wtr);
113
}
114
115
static void print_perf_plain(int pid, int fd, __u32 prog_id, __u32 fd_type,
116
char *buf, __u64 probe_offset, __u64 probe_addr)
117
{
118
printf("pid %d fd %d: prog_id %u ", pid, fd, prog_id);
119
switch (fd_type) {
120
case BPF_FD_TYPE_RAW_TRACEPOINT:
121
printf("raw_tracepoint %s\n", buf);
122
break;
123
case BPF_FD_TYPE_TRACEPOINT:
124
printf("tracepoint %s\n", buf);
125
break;
126
case BPF_FD_TYPE_KPROBE:
127
if (buf[0] != '\0')
128
printf("kprobe func %s offset %llu\n", buf,
129
probe_offset);
130
else
131
printf("kprobe addr %llu\n", probe_addr);
132
break;
133
case BPF_FD_TYPE_KRETPROBE:
134
if (buf[0] != '\0')
135
printf("kretprobe func %s offset %llu\n", buf,
136
probe_offset);
137
else
138
printf("kretprobe addr %llu\n", probe_addr);
139
break;
140
case BPF_FD_TYPE_UPROBE:
141
printf("uprobe filename %s offset %llu\n", buf, probe_offset);
142
break;
143
case BPF_FD_TYPE_URETPROBE:
144
printf("uretprobe filename %s offset %llu\n", buf,
145
probe_offset);
146
break;
147
default:
148
break;
149
}
150
}
151
152
static int show_proc(void)
153
{
154
struct dirent *proc_de, *pid_fd_de;
155
__u64 probe_offset, probe_addr;
156
__u32 len, prog_id, fd_type;
157
DIR *proc, *pid_fd;
158
int err, pid, fd;
159
const char *pch;
160
char buf[4096];
161
162
proc = opendir("/proc");
163
if (!proc)
164
return -1;
165
166
while ((proc_de = readdir(proc))) {
167
pid = 0;
168
pch = proc_de->d_name;
169
170
/* pid should be all numbers */
171
while (isdigit(*pch)) {
172
pid = pid * 10 + *pch - '0';
173
pch++;
174
}
175
if (*pch != '\0')
176
continue;
177
178
err = snprintf(buf, sizeof(buf), "/proc/%s/fd", proc_de->d_name);
179
if (err < 0 || err >= (int)sizeof(buf))
180
continue;
181
182
pid_fd = opendir(buf);
183
if (!pid_fd)
184
continue;
185
186
while ((pid_fd_de = readdir(pid_fd))) {
187
fd = 0;
188
pch = pid_fd_de->d_name;
189
190
/* fd should be all numbers */
191
while (isdigit(*pch)) {
192
fd = fd * 10 + *pch - '0';
193
pch++;
194
}
195
if (*pch != '\0')
196
continue;
197
198
/* query (pid, fd) for potential perf events */
199
len = sizeof(buf);
200
err = bpf_task_fd_query(pid, fd, 0, buf, &len,
201
&prog_id, &fd_type,
202
&probe_offset, &probe_addr);
203
if (err < 0)
204
continue;
205
206
if (json_output)
207
print_perf_json(pid, fd, prog_id, fd_type, buf,
208
probe_offset, probe_addr);
209
else
210
print_perf_plain(pid, fd, prog_id, fd_type, buf,
211
probe_offset, probe_addr);
212
}
213
closedir(pid_fd);
214
}
215
closedir(proc);
216
return 0;
217
}
218
219
static int do_show(int argc, char **argv)
220
{
221
int err;
222
223
if (!has_perf_query_support())
224
return -1;
225
226
if (json_output)
227
jsonw_start_array(json_wtr);
228
err = show_proc();
229
if (json_output)
230
jsonw_end_array(json_wtr);
231
232
return err;
233
}
234
235
static int do_help(int argc, char **argv)
236
{
237
fprintf(stderr,
238
"Usage: %1$s %2$s { show | list }\n"
239
" %1$s %2$s help\n"
240
"\n"
241
" " HELP_SPEC_OPTIONS " }\n"
242
"",
243
bin_name, argv[-2]);
244
245
return 0;
246
}
247
248
static const struct cmd cmds[] = {
249
{ "show", do_show },
250
{ "list", do_show },
251
{ "help", do_help },
252
{ 0 }
253
};
254
255
int do_perf(int argc, char **argv)
256
{
257
return cmd_select(cmds, argc, argv, do_help);
258
}
259
260