xref: /aosp_15_r20/external/bpftool/src/perf.c (revision 858ea5e570667251cdc31d3fe7b846b591105938)
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