Linux Audio

Check our new training course

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