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