xref: /aosp_15_r20/external/bcc/libbpf-tools/syscount.c (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2*387f9dfdSAndroid Build Coastguard Worker // Copyright (c) 2020 Anton Protopopov
3*387f9dfdSAndroid Build Coastguard Worker //
4*387f9dfdSAndroid Build Coastguard Worker // Based on syscount(8) from BCC by Sasha Goldshtein
5*387f9dfdSAndroid Build Coastguard Worker #include <unistd.h>
6*387f9dfdSAndroid Build Coastguard Worker #include <signal.h>
7*387f9dfdSAndroid Build Coastguard Worker #include <fcntl.h>
8*387f9dfdSAndroid Build Coastguard Worker #include <time.h>
9*387f9dfdSAndroid Build Coastguard Worker #include <unistd.h>
10*387f9dfdSAndroid Build Coastguard Worker #include <argp.h>
11*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf.h>
12*387f9dfdSAndroid Build Coastguard Worker #include "syscount.h"
13*387f9dfdSAndroid Build Coastguard Worker #include "syscount.skel.h"
14*387f9dfdSAndroid Build Coastguard Worker #include "errno_helpers.h"
15*387f9dfdSAndroid Build Coastguard Worker #include "syscall_helpers.h"
16*387f9dfdSAndroid Build Coastguard Worker #include "btf_helpers.h"
17*387f9dfdSAndroid Build Coastguard Worker #include "trace_helpers.h"
18*387f9dfdSAndroid Build Coastguard Worker 
19*387f9dfdSAndroid Build Coastguard Worker /* This structure extends data_t by adding a key item which should be sorted
20*387f9dfdSAndroid Build Coastguard Worker  * together with the count and total_ns fields */
21*387f9dfdSAndroid Build Coastguard Worker struct data_ext_t {
22*387f9dfdSAndroid Build Coastguard Worker 	__u64 count;
23*387f9dfdSAndroid Build Coastguard Worker 	__u64 total_ns;
24*387f9dfdSAndroid Build Coastguard Worker 	char comm[TASK_COMM_LEN];
25*387f9dfdSAndroid Build Coastguard Worker 	__u32 key;
26*387f9dfdSAndroid Build Coastguard Worker };
27*387f9dfdSAndroid Build Coastguard Worker 
28*387f9dfdSAndroid Build Coastguard Worker 
29*387f9dfdSAndroid Build Coastguard Worker #define warn(...) fprintf(stderr, __VA_ARGS__)
30*387f9dfdSAndroid Build Coastguard Worker 
31*387f9dfdSAndroid Build Coastguard Worker const char *argp_program_version = "syscount 0.1";
32*387f9dfdSAndroid Build Coastguard Worker const char *argp_program_bug_address =
33*387f9dfdSAndroid Build Coastguard Worker 	"https://github.com/iovisor/bcc/tree/master/libbpf-tools";
34*387f9dfdSAndroid Build Coastguard Worker static const char argp_program_doc[] =
35*387f9dfdSAndroid Build Coastguard Worker "\nsyscount: summarize syscall counts and latencies\n"
36*387f9dfdSAndroid Build Coastguard Worker "\n"
37*387f9dfdSAndroid Build Coastguard Worker "EXAMPLES:\n"
38*387f9dfdSAndroid Build Coastguard Worker "    syscount                 # print top 10 syscalls by count every second\n"
39*387f9dfdSAndroid Build Coastguard Worker "    syscount -p $(pidof dd)  # look only at a particular process\n"
40*387f9dfdSAndroid Build Coastguard Worker "    syscount -L              # measure and sort output by latency\n"
41*387f9dfdSAndroid Build Coastguard Worker "    syscount -P              # group statistics by pid, not by syscall\n"
42*387f9dfdSAndroid Build Coastguard Worker "    syscount -x -i 5         # count only failed syscalls\n"
43*387f9dfdSAndroid Build Coastguard Worker "    syscount -e ENOENT -i 5  # count only syscalls failed with a given errno\n"
44*387f9dfdSAndroid Build Coastguard Worker "    syscount -c CG           # Trace process under cgroupsPath CG\n";
45*387f9dfdSAndroid Build Coastguard Worker ;
46*387f9dfdSAndroid Build Coastguard Worker 
47*387f9dfdSAndroid Build Coastguard Worker static const struct argp_option opts[] = {
48*387f9dfdSAndroid Build Coastguard Worker 	{ "verbose", 'v', NULL, 0, "Verbose debug output" },
49*387f9dfdSAndroid Build Coastguard Worker 	{ "pid", 'p', "PID", 0, "Process PID to trace" },
50*387f9dfdSAndroid Build Coastguard Worker 	{ "interval", 'i', "INTERVAL", 0, "Print summary at this interval"
51*387f9dfdSAndroid Build Coastguard Worker 				" (seconds), 0 for infinite wait (default)" },
52*387f9dfdSAndroid Build Coastguard Worker 	{ "duration", 'd', "DURATION", 0, "Total tracing duration (seconds)" },
53*387f9dfdSAndroid Build Coastguard Worker 	{ "top", 'T', "TOP", 0, "Print only the top syscalls (default 10)" },
54*387f9dfdSAndroid Build Coastguard Worker 	{ "cgroup", 'c', "/sys/fs/cgroup/unified/<CG>", 0, "Trace process in cgroup path"},
55*387f9dfdSAndroid Build Coastguard Worker 	{ "failures", 'x', NULL, 0, "Trace only failed syscalls" },
56*387f9dfdSAndroid Build Coastguard Worker 	{ "latency", 'L', NULL, 0, "Collect syscall latency" },
57*387f9dfdSAndroid Build Coastguard Worker 	{ "milliseconds", 'm', NULL, 0, "Display latency in milliseconds"
58*387f9dfdSAndroid Build Coastguard Worker 					" (default: microseconds)" },
59*387f9dfdSAndroid Build Coastguard Worker 	{ "process", 'P', NULL, 0, "Count by process and not by syscall" },
60*387f9dfdSAndroid Build Coastguard Worker 	{ "errno", 'e', "ERRNO", 0, "Trace only syscalls that return this error"
61*387f9dfdSAndroid Build Coastguard Worker 				 "(numeric or EPERM, etc.)" },
62*387f9dfdSAndroid Build Coastguard Worker 	{ "list", 'l', NULL, 0, "Print list of recognized syscalls and exit" },
63*387f9dfdSAndroid Build Coastguard Worker 	{ NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" },
64*387f9dfdSAndroid Build Coastguard Worker 	{},
65*387f9dfdSAndroid Build Coastguard Worker };
66*387f9dfdSAndroid Build Coastguard Worker 
67*387f9dfdSAndroid Build Coastguard Worker static struct env {
68*387f9dfdSAndroid Build Coastguard Worker 	bool list_syscalls;
69*387f9dfdSAndroid Build Coastguard Worker 	bool milliseconds;
70*387f9dfdSAndroid Build Coastguard Worker 	bool failures;
71*387f9dfdSAndroid Build Coastguard Worker 	bool verbose;
72*387f9dfdSAndroid Build Coastguard Worker 	bool latency;
73*387f9dfdSAndroid Build Coastguard Worker 	bool process;
74*387f9dfdSAndroid Build Coastguard Worker 	int filter_errno;
75*387f9dfdSAndroid Build Coastguard Worker 	int interval;
76*387f9dfdSAndroid Build Coastguard Worker 	int duration;
77*387f9dfdSAndroid Build Coastguard Worker 	int top;
78*387f9dfdSAndroid Build Coastguard Worker 	pid_t pid;
79*387f9dfdSAndroid Build Coastguard Worker 	char *cgroupspath;
80*387f9dfdSAndroid Build Coastguard Worker 	bool cg;
81*387f9dfdSAndroid Build Coastguard Worker } env = {
82*387f9dfdSAndroid Build Coastguard Worker 	.top = 10,
83*387f9dfdSAndroid Build Coastguard Worker };
84*387f9dfdSAndroid Build Coastguard Worker 
get_int(const char * arg,int * ret,int min,int max)85*387f9dfdSAndroid Build Coastguard Worker static int get_int(const char *arg, int *ret, int min, int max)
86*387f9dfdSAndroid Build Coastguard Worker {
87*387f9dfdSAndroid Build Coastguard Worker 	char *end;
88*387f9dfdSAndroid Build Coastguard Worker 	long val;
89*387f9dfdSAndroid Build Coastguard Worker 
90*387f9dfdSAndroid Build Coastguard Worker 	errno = 0;
91*387f9dfdSAndroid Build Coastguard Worker 	val = strtol(arg, &end, 10);
92*387f9dfdSAndroid Build Coastguard Worker 	if (errno) {
93*387f9dfdSAndroid Build Coastguard Worker 		warn("strtol: %s: %s\n", arg, strerror(errno));
94*387f9dfdSAndroid Build Coastguard Worker 		return -1;
95*387f9dfdSAndroid Build Coastguard Worker 	} else if (end == arg || val < min || val > max) {
96*387f9dfdSAndroid Build Coastguard Worker 		return -1;
97*387f9dfdSAndroid Build Coastguard Worker 	}
98*387f9dfdSAndroid Build Coastguard Worker 	if (ret)
99*387f9dfdSAndroid Build Coastguard Worker 		*ret = val;
100*387f9dfdSAndroid Build Coastguard Worker 	return 0;
101*387f9dfdSAndroid Build Coastguard Worker }
102*387f9dfdSAndroid Build Coastguard Worker 
libbpf_print_fn(enum libbpf_print_level level,const char * format,va_list args)103*387f9dfdSAndroid Build Coastguard Worker static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
104*387f9dfdSAndroid Build Coastguard Worker {
105*387f9dfdSAndroid Build Coastguard Worker 	if (level == LIBBPF_DEBUG && !env.verbose)
106*387f9dfdSAndroid Build Coastguard Worker 		return 0;
107*387f9dfdSAndroid Build Coastguard Worker 
108*387f9dfdSAndroid Build Coastguard Worker 	return vfprintf(stderr, format, args);
109*387f9dfdSAndroid Build Coastguard Worker }
110*387f9dfdSAndroid Build Coastguard Worker 
compar_count(const void * dx,const void * dy)111*387f9dfdSAndroid Build Coastguard Worker static int compar_count(const void *dx, const void *dy)
112*387f9dfdSAndroid Build Coastguard Worker {
113*387f9dfdSAndroid Build Coastguard Worker 	__u64 x = ((struct data_ext_t *) dx)->count;
114*387f9dfdSAndroid Build Coastguard Worker 	__u64 y = ((struct data_ext_t *) dy)->count;
115*387f9dfdSAndroid Build Coastguard Worker 	return x > y ? -1 : !(x == y);
116*387f9dfdSAndroid Build Coastguard Worker }
117*387f9dfdSAndroid Build Coastguard Worker 
compar_latency(const void * dx,const void * dy)118*387f9dfdSAndroid Build Coastguard Worker static int compar_latency(const void *dx, const void *dy)
119*387f9dfdSAndroid Build Coastguard Worker {
120*387f9dfdSAndroid Build Coastguard Worker 	__u64 x = ((struct data_ext_t *) dx)->total_ns;
121*387f9dfdSAndroid Build Coastguard Worker 	__u64 y = ((struct data_ext_t *) dy)->total_ns;
122*387f9dfdSAndroid Build Coastguard Worker 	return x > y ? -1 : !(x == y);
123*387f9dfdSAndroid Build Coastguard Worker }
124*387f9dfdSAndroid Build Coastguard Worker 
agg_col(struct data_ext_t * val,char * buf,size_t size)125*387f9dfdSAndroid Build Coastguard Worker static const char *agg_col(struct data_ext_t *val, char *buf, size_t size)
126*387f9dfdSAndroid Build Coastguard Worker {
127*387f9dfdSAndroid Build Coastguard Worker 	if (env.process) {
128*387f9dfdSAndroid Build Coastguard Worker 		snprintf(buf, size, "%-6u %-15s", val->key, val->comm);
129*387f9dfdSAndroid Build Coastguard Worker 	} else {
130*387f9dfdSAndroid Build Coastguard Worker 		syscall_name(val->key, buf, size);
131*387f9dfdSAndroid Build Coastguard Worker 	}
132*387f9dfdSAndroid Build Coastguard Worker 	return buf;
133*387f9dfdSAndroid Build Coastguard Worker }
134*387f9dfdSAndroid Build Coastguard Worker 
agg_colname(void)135*387f9dfdSAndroid Build Coastguard Worker static const char *agg_colname(void)
136*387f9dfdSAndroid Build Coastguard Worker {
137*387f9dfdSAndroid Build Coastguard Worker 	return (env.process) ? "PID    COMM" : "SYSCALL";
138*387f9dfdSAndroid Build Coastguard Worker }
139*387f9dfdSAndroid Build Coastguard Worker 
time_colname(void)140*387f9dfdSAndroid Build Coastguard Worker static const char *time_colname(void)
141*387f9dfdSAndroid Build Coastguard Worker {
142*387f9dfdSAndroid Build Coastguard Worker 	return (env.milliseconds) ? "TIME (ms)" : "TIME (us)";
143*387f9dfdSAndroid Build Coastguard Worker }
144*387f9dfdSAndroid Build Coastguard Worker 
print_latency_header(void)145*387f9dfdSAndroid Build Coastguard Worker static void print_latency_header(void)
146*387f9dfdSAndroid Build Coastguard Worker {
147*387f9dfdSAndroid Build Coastguard Worker 	printf("%-22s %8s %16s\n", agg_colname(), "COUNT", time_colname());
148*387f9dfdSAndroid Build Coastguard Worker }
149*387f9dfdSAndroid Build Coastguard Worker 
print_count_header(void)150*387f9dfdSAndroid Build Coastguard Worker static void print_count_header(void)
151*387f9dfdSAndroid Build Coastguard Worker {
152*387f9dfdSAndroid Build Coastguard Worker 	printf("%-22s %8s\n", agg_colname(), "COUNT");
153*387f9dfdSAndroid Build Coastguard Worker }
154*387f9dfdSAndroid Build Coastguard Worker 
print_latency(struct data_ext_t * vals,size_t count)155*387f9dfdSAndroid Build Coastguard Worker static void print_latency(struct data_ext_t *vals, size_t count)
156*387f9dfdSAndroid Build Coastguard Worker {
157*387f9dfdSAndroid Build Coastguard Worker 	double div = env.milliseconds ? 1000000.0 : 1000.0;
158*387f9dfdSAndroid Build Coastguard Worker 	char buf[2 * TASK_COMM_LEN];
159*387f9dfdSAndroid Build Coastguard Worker 	int i;
160*387f9dfdSAndroid Build Coastguard Worker 
161*387f9dfdSAndroid Build Coastguard Worker 	print_latency_header();
162*387f9dfdSAndroid Build Coastguard Worker 	for (i = 0; i < count && i < env.top; i++)
163*387f9dfdSAndroid Build Coastguard Worker 		printf("%-22s %8llu %16.3lf\n",
164*387f9dfdSAndroid Build Coastguard Worker 		       agg_col(&vals[i], buf, sizeof(buf)),
165*387f9dfdSAndroid Build Coastguard Worker 		       vals[i].count, vals[i].total_ns / div);
166*387f9dfdSAndroid Build Coastguard Worker 	printf("\n");
167*387f9dfdSAndroid Build Coastguard Worker }
168*387f9dfdSAndroid Build Coastguard Worker 
print_count(struct data_ext_t * vals,size_t count)169*387f9dfdSAndroid Build Coastguard Worker static void print_count(struct data_ext_t *vals, size_t count)
170*387f9dfdSAndroid Build Coastguard Worker {
171*387f9dfdSAndroid Build Coastguard Worker 	char buf[2 * TASK_COMM_LEN];
172*387f9dfdSAndroid Build Coastguard Worker 	int i;
173*387f9dfdSAndroid Build Coastguard Worker 
174*387f9dfdSAndroid Build Coastguard Worker 	print_count_header();
175*387f9dfdSAndroid Build Coastguard Worker 	for (i = 0; i < count && i < env.top; i++)
176*387f9dfdSAndroid Build Coastguard Worker 		printf("%-22s %8llu\n",
177*387f9dfdSAndroid Build Coastguard Worker 		       agg_col(&vals[i], buf, sizeof(buf)), vals[i].count);
178*387f9dfdSAndroid Build Coastguard Worker 	printf("\n");
179*387f9dfdSAndroid Build Coastguard Worker }
180*387f9dfdSAndroid Build Coastguard Worker 
print_timestamp()181*387f9dfdSAndroid Build Coastguard Worker static void print_timestamp()
182*387f9dfdSAndroid Build Coastguard Worker {
183*387f9dfdSAndroid Build Coastguard Worker 	time_t now = time(NULL);
184*387f9dfdSAndroid Build Coastguard Worker 	struct tm tm;
185*387f9dfdSAndroid Build Coastguard Worker 
186*387f9dfdSAndroid Build Coastguard Worker 	if (localtime_r(&now, &tm))
187*387f9dfdSAndroid Build Coastguard Worker 		printf("[%02d:%02d:%02d]\n", tm.tm_hour, tm.tm_min, tm.tm_sec);
188*387f9dfdSAndroid Build Coastguard Worker 	else
189*387f9dfdSAndroid Build Coastguard Worker 		warn("localtime_r: %s", strerror(errno));
190*387f9dfdSAndroid Build Coastguard Worker }
191*387f9dfdSAndroid Build Coastguard Worker 
192*387f9dfdSAndroid Build Coastguard Worker static bool batch_map_ops = true; /* hope for the best */
193*387f9dfdSAndroid Build Coastguard Worker 
read_vals_batch(int fd,struct data_ext_t * vals,__u32 * count)194*387f9dfdSAndroid Build Coastguard Worker static bool read_vals_batch(int fd, struct data_ext_t *vals, __u32 *count)
195*387f9dfdSAndroid Build Coastguard Worker {
196*387f9dfdSAndroid Build Coastguard Worker 	struct data_t orig_vals[*count];
197*387f9dfdSAndroid Build Coastguard Worker 	void *in = NULL, *out;
198*387f9dfdSAndroid Build Coastguard Worker 	__u32 i, n, n_read = 0;
199*387f9dfdSAndroid Build Coastguard Worker 	__u32 keys[*count];
200*387f9dfdSAndroid Build Coastguard Worker 	int err = 0;
201*387f9dfdSAndroid Build Coastguard Worker 
202*387f9dfdSAndroid Build Coastguard Worker 	while (n_read < *count && !err) {
203*387f9dfdSAndroid Build Coastguard Worker 		n = *count - n_read;
204*387f9dfdSAndroid Build Coastguard Worker 		err = bpf_map_lookup_and_delete_batch(fd, &in, &out,
205*387f9dfdSAndroid Build Coastguard Worker 				keys + n_read, orig_vals + n_read, &n, NULL);
206*387f9dfdSAndroid Build Coastguard Worker 		if (err && errno != ENOENT) {
207*387f9dfdSAndroid Build Coastguard Worker 			/* we want to propagate EINVAL upper, so that
208*387f9dfdSAndroid Build Coastguard Worker 			 * the batch_map_ops flag is set to false */
209*387f9dfdSAndroid Build Coastguard Worker 			if (errno != EINVAL)
210*387f9dfdSAndroid Build Coastguard Worker 				warn("bpf_map_lookup_and_delete_batch: %s\n",
211*387f9dfdSAndroid Build Coastguard Worker 				     strerror(-err));
212*387f9dfdSAndroid Build Coastguard Worker 			return false;
213*387f9dfdSAndroid Build Coastguard Worker 		}
214*387f9dfdSAndroid Build Coastguard Worker 		n_read += n;
215*387f9dfdSAndroid Build Coastguard Worker 		in = out;
216*387f9dfdSAndroid Build Coastguard Worker 	}
217*387f9dfdSAndroid Build Coastguard Worker 
218*387f9dfdSAndroid Build Coastguard Worker 	for (i = 0; i < n_read; i++) {
219*387f9dfdSAndroid Build Coastguard Worker 		vals[i].count = orig_vals[i].count;
220*387f9dfdSAndroid Build Coastguard Worker 		vals[i].total_ns = orig_vals[i].total_ns;
221*387f9dfdSAndroid Build Coastguard Worker 		vals[i].key = keys[i];
222*387f9dfdSAndroid Build Coastguard Worker 		strncpy(vals[i].comm, orig_vals[i].comm, TASK_COMM_LEN);
223*387f9dfdSAndroid Build Coastguard Worker 	}
224*387f9dfdSAndroid Build Coastguard Worker 
225*387f9dfdSAndroid Build Coastguard Worker 	*count = n_read;
226*387f9dfdSAndroid Build Coastguard Worker 	return true;
227*387f9dfdSAndroid Build Coastguard Worker }
228*387f9dfdSAndroid Build Coastguard Worker 
read_vals(int fd,struct data_ext_t * vals,__u32 * count)229*387f9dfdSAndroid Build Coastguard Worker static bool read_vals(int fd, struct data_ext_t *vals, __u32 *count)
230*387f9dfdSAndroid Build Coastguard Worker {
231*387f9dfdSAndroid Build Coastguard Worker 	__u32 keys[MAX_ENTRIES];
232*387f9dfdSAndroid Build Coastguard Worker 	struct data_t val;
233*387f9dfdSAndroid Build Coastguard Worker 	__u32 key = -1;
234*387f9dfdSAndroid Build Coastguard Worker 	__u32 next_key;
235*387f9dfdSAndroid Build Coastguard Worker 	int i = 0, j;
236*387f9dfdSAndroid Build Coastguard Worker 	int err;
237*387f9dfdSAndroid Build Coastguard Worker 
238*387f9dfdSAndroid Build Coastguard Worker 	if (batch_map_ops) {
239*387f9dfdSAndroid Build Coastguard Worker 		bool ok = read_vals_batch(fd, vals, count);
240*387f9dfdSAndroid Build Coastguard Worker 		if (!ok && errno == EINVAL) {
241*387f9dfdSAndroid Build Coastguard Worker 			/* fall back to a racy variant */
242*387f9dfdSAndroid Build Coastguard Worker 			batch_map_ops = false;
243*387f9dfdSAndroid Build Coastguard Worker 		} else {
244*387f9dfdSAndroid Build Coastguard Worker 			return ok;
245*387f9dfdSAndroid Build Coastguard Worker 		}
246*387f9dfdSAndroid Build Coastguard Worker 	}
247*387f9dfdSAndroid Build Coastguard Worker 
248*387f9dfdSAndroid Build Coastguard Worker 	if (!vals || !count || !*count)
249*387f9dfdSAndroid Build Coastguard Worker 		return true;
250*387f9dfdSAndroid Build Coastguard Worker 
251*387f9dfdSAndroid Build Coastguard Worker 	for (key = -1; i < *count; ) {
252*387f9dfdSAndroid Build Coastguard Worker 		err = bpf_map_get_next_key(fd, &key, &next_key);
253*387f9dfdSAndroid Build Coastguard Worker 		if (err && errno != ENOENT) {
254*387f9dfdSAndroid Build Coastguard Worker 			warn("failed to get next key: %s\n", strerror(errno));
255*387f9dfdSAndroid Build Coastguard Worker 			return false;
256*387f9dfdSAndroid Build Coastguard Worker 		} else if (err) {
257*387f9dfdSAndroid Build Coastguard Worker 			break;
258*387f9dfdSAndroid Build Coastguard Worker 		}
259*387f9dfdSAndroid Build Coastguard Worker 		key = keys[i++] = next_key;
260*387f9dfdSAndroid Build Coastguard Worker 	}
261*387f9dfdSAndroid Build Coastguard Worker 
262*387f9dfdSAndroid Build Coastguard Worker 	for (j = 0; j < i; j++) {
263*387f9dfdSAndroid Build Coastguard Worker 		err = bpf_map_lookup_elem(fd, &keys[j], &val);
264*387f9dfdSAndroid Build Coastguard Worker 		if (err && errno != ENOENT) {
265*387f9dfdSAndroid Build Coastguard Worker 			warn("failed to lookup element: %s\n", strerror(errno));
266*387f9dfdSAndroid Build Coastguard Worker 			return false;
267*387f9dfdSAndroid Build Coastguard Worker 		}
268*387f9dfdSAndroid Build Coastguard Worker 		vals[j].count = val.count;
269*387f9dfdSAndroid Build Coastguard Worker 		vals[j].total_ns = val.total_ns;
270*387f9dfdSAndroid Build Coastguard Worker 		vals[j].key = keys[j];
271*387f9dfdSAndroid Build Coastguard Worker 		memcpy(vals[j].comm, val.comm, TASK_COMM_LEN);
272*387f9dfdSAndroid Build Coastguard Worker 	}
273*387f9dfdSAndroid Build Coastguard Worker 
274*387f9dfdSAndroid Build Coastguard Worker 	/* There is a race here: system calls which are represented by keys
275*387f9dfdSAndroid Build Coastguard Worker 	 * above and happened between lookup and delete will be ignored.  This
276*387f9dfdSAndroid Build Coastguard Worker 	 * will be fixed in future by using bpf_map_lookup_and_delete_batch,
277*387f9dfdSAndroid Build Coastguard Worker 	 * but this function is too fresh to use it in bcc. */
278*387f9dfdSAndroid Build Coastguard Worker 
279*387f9dfdSAndroid Build Coastguard Worker 	for (j = 0; j < i; j++) {
280*387f9dfdSAndroid Build Coastguard Worker 		err = bpf_map_delete_elem(fd, &keys[j]);
281*387f9dfdSAndroid Build Coastguard Worker 		if (err) {
282*387f9dfdSAndroid Build Coastguard Worker 			warn("failed to delete element: %s\n", strerror(errno));
283*387f9dfdSAndroid Build Coastguard Worker 			return false;
284*387f9dfdSAndroid Build Coastguard Worker 		}
285*387f9dfdSAndroid Build Coastguard Worker 	}
286*387f9dfdSAndroid Build Coastguard Worker 
287*387f9dfdSAndroid Build Coastguard Worker 	*count = i;
288*387f9dfdSAndroid Build Coastguard Worker 	return true;
289*387f9dfdSAndroid Build Coastguard Worker }
290*387f9dfdSAndroid Build Coastguard Worker 
parse_arg(int key,char * arg,struct argp_state * state)291*387f9dfdSAndroid Build Coastguard Worker static error_t parse_arg(int key, char *arg, struct argp_state *state)
292*387f9dfdSAndroid Build Coastguard Worker {
293*387f9dfdSAndroid Build Coastguard Worker 	int number;
294*387f9dfdSAndroid Build Coastguard Worker 	int err;
295*387f9dfdSAndroid Build Coastguard Worker 
296*387f9dfdSAndroid Build Coastguard Worker 	switch (key) {
297*387f9dfdSAndroid Build Coastguard Worker 	case 'h':
298*387f9dfdSAndroid Build Coastguard Worker 		argp_state_help(state, stderr, ARGP_HELP_STD_HELP);
299*387f9dfdSAndroid Build Coastguard Worker 		break;
300*387f9dfdSAndroid Build Coastguard Worker 	case 'v':
301*387f9dfdSAndroid Build Coastguard Worker 		env.verbose = true;
302*387f9dfdSAndroid Build Coastguard Worker 		break;
303*387f9dfdSAndroid Build Coastguard Worker 	case 'x':
304*387f9dfdSAndroid Build Coastguard Worker 		env.failures = true;
305*387f9dfdSAndroid Build Coastguard Worker 		break;
306*387f9dfdSAndroid Build Coastguard Worker 	case 'L':
307*387f9dfdSAndroid Build Coastguard Worker 		env.latency = true;
308*387f9dfdSAndroid Build Coastguard Worker 		break;
309*387f9dfdSAndroid Build Coastguard Worker 	case 'm':
310*387f9dfdSAndroid Build Coastguard Worker 		env.milliseconds = true;
311*387f9dfdSAndroid Build Coastguard Worker 		break;
312*387f9dfdSAndroid Build Coastguard Worker 	case 'P':
313*387f9dfdSAndroid Build Coastguard Worker 		env.process = true;
314*387f9dfdSAndroid Build Coastguard Worker 		break;
315*387f9dfdSAndroid Build Coastguard Worker 	case 'p':
316*387f9dfdSAndroid Build Coastguard Worker 		err = get_int(arg, &env.pid, 1, INT_MAX);
317*387f9dfdSAndroid Build Coastguard Worker 		if (err) {
318*387f9dfdSAndroid Build Coastguard Worker 			warn("invalid PID: %s\n", arg);
319*387f9dfdSAndroid Build Coastguard Worker 			argp_usage(state);
320*387f9dfdSAndroid Build Coastguard Worker 		}
321*387f9dfdSAndroid Build Coastguard Worker 		break;
322*387f9dfdSAndroid Build Coastguard Worker 	case 'i':
323*387f9dfdSAndroid Build Coastguard Worker 		err = get_int(arg, &env.interval, 0, INT_MAX);
324*387f9dfdSAndroid Build Coastguard Worker 		if (err) {
325*387f9dfdSAndroid Build Coastguard Worker 			warn("invalid INTERVAL: %s\n", arg);
326*387f9dfdSAndroid Build Coastguard Worker 			argp_usage(state);
327*387f9dfdSAndroid Build Coastguard Worker 		}
328*387f9dfdSAndroid Build Coastguard Worker 		break;
329*387f9dfdSAndroid Build Coastguard Worker 	case 'd':
330*387f9dfdSAndroid Build Coastguard Worker 		err = get_int(arg, &env.duration, 1, INT_MAX);
331*387f9dfdSAndroid Build Coastguard Worker 		if (err) {
332*387f9dfdSAndroid Build Coastguard Worker 			warn("invalid DURATION: %s\n", arg);
333*387f9dfdSAndroid Build Coastguard Worker 			argp_usage(state);
334*387f9dfdSAndroid Build Coastguard Worker 		}
335*387f9dfdSAndroid Build Coastguard Worker 		break;
336*387f9dfdSAndroid Build Coastguard Worker 	case 'T':
337*387f9dfdSAndroid Build Coastguard Worker 		err = get_int(arg, &env.top, 1, INT_MAX);
338*387f9dfdSAndroid Build Coastguard Worker 		if (err) {
339*387f9dfdSAndroid Build Coastguard Worker 			warn("invalid TOP: %s\n", arg);
340*387f9dfdSAndroid Build Coastguard Worker 			argp_usage(state);
341*387f9dfdSAndroid Build Coastguard Worker 		}
342*387f9dfdSAndroid Build Coastguard Worker 		break;
343*387f9dfdSAndroid Build Coastguard Worker 	case 'c':
344*387f9dfdSAndroid Build Coastguard Worker 		env.cgroupspath = arg;
345*387f9dfdSAndroid Build Coastguard Worker 		env.cg = true;
346*387f9dfdSAndroid Build Coastguard Worker 		break;
347*387f9dfdSAndroid Build Coastguard Worker 	case 'e':
348*387f9dfdSAndroid Build Coastguard Worker 		err = get_int(arg, &number, 1, INT_MAX);
349*387f9dfdSAndroid Build Coastguard Worker 		if (err) {
350*387f9dfdSAndroid Build Coastguard Worker 			number = errno_by_name(arg);
351*387f9dfdSAndroid Build Coastguard Worker 			if (number < 0) {
352*387f9dfdSAndroid Build Coastguard Worker 				warn("invalid errno: %s (bad, or can't "
353*387f9dfdSAndroid Build Coastguard Worker 				     "parse dynamically; consider using "
354*387f9dfdSAndroid Build Coastguard Worker 				     "numeric value and/or installing the "
355*387f9dfdSAndroid Build Coastguard Worker 				     "errno program from moreutils)\n", arg);
356*387f9dfdSAndroid Build Coastguard Worker 				argp_usage(state);
357*387f9dfdSAndroid Build Coastguard Worker 			}
358*387f9dfdSAndroid Build Coastguard Worker 		}
359*387f9dfdSAndroid Build Coastguard Worker 		env.filter_errno = number;
360*387f9dfdSAndroid Build Coastguard Worker 		break;
361*387f9dfdSAndroid Build Coastguard Worker 	case 'l':
362*387f9dfdSAndroid Build Coastguard Worker 		env.list_syscalls = true;
363*387f9dfdSAndroid Build Coastguard Worker 		break;
364*387f9dfdSAndroid Build Coastguard Worker 	default:
365*387f9dfdSAndroid Build Coastguard Worker 		return ARGP_ERR_UNKNOWN;
366*387f9dfdSAndroid Build Coastguard Worker 	}
367*387f9dfdSAndroid Build Coastguard Worker 	return 0;
368*387f9dfdSAndroid Build Coastguard Worker }
369*387f9dfdSAndroid Build Coastguard Worker 
370*387f9dfdSAndroid Build Coastguard Worker static volatile sig_atomic_t hang_on = 1;
371*387f9dfdSAndroid Build Coastguard Worker 
sig_int(int signo)372*387f9dfdSAndroid Build Coastguard Worker void sig_int(int signo)
373*387f9dfdSAndroid Build Coastguard Worker {
374*387f9dfdSAndroid Build Coastguard Worker 	hang_on = 0;
375*387f9dfdSAndroid Build Coastguard Worker }
376*387f9dfdSAndroid Build Coastguard Worker 
main(int argc,char ** argv)377*387f9dfdSAndroid Build Coastguard Worker int main(int argc, char **argv)
378*387f9dfdSAndroid Build Coastguard Worker {
379*387f9dfdSAndroid Build Coastguard Worker 	LIBBPF_OPTS(bpf_object_open_opts, open_opts);
380*387f9dfdSAndroid Build Coastguard Worker 	void (*print)(struct data_ext_t *, size_t);
381*387f9dfdSAndroid Build Coastguard Worker 	int (*compar)(const void *, const void *);
382*387f9dfdSAndroid Build Coastguard Worker 	static const struct argp argp = {
383*387f9dfdSAndroid Build Coastguard Worker 		.options = opts,
384*387f9dfdSAndroid Build Coastguard Worker 		.parser = parse_arg,
385*387f9dfdSAndroid Build Coastguard Worker 		.doc = argp_program_doc,
386*387f9dfdSAndroid Build Coastguard Worker 	};
387*387f9dfdSAndroid Build Coastguard Worker 	struct data_ext_t vals[MAX_ENTRIES];
388*387f9dfdSAndroid Build Coastguard Worker 	struct syscount_bpf *obj;
389*387f9dfdSAndroid Build Coastguard Worker 	int seconds = 0;
390*387f9dfdSAndroid Build Coastguard Worker 	__u32 count;
391*387f9dfdSAndroid Build Coastguard Worker 	int err;
392*387f9dfdSAndroid Build Coastguard Worker 	int idx, cg_map_fd;
393*387f9dfdSAndroid Build Coastguard Worker 	int cgfd = -1;
394*387f9dfdSAndroid Build Coastguard Worker 
395*387f9dfdSAndroid Build Coastguard Worker 	init_syscall_names();
396*387f9dfdSAndroid Build Coastguard Worker 
397*387f9dfdSAndroid Build Coastguard Worker 	err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
398*387f9dfdSAndroid Build Coastguard Worker 	if (err)
399*387f9dfdSAndroid Build Coastguard Worker 		goto free_names;
400*387f9dfdSAndroid Build Coastguard Worker 
401*387f9dfdSAndroid Build Coastguard Worker 	if (env.list_syscalls) {
402*387f9dfdSAndroid Build Coastguard Worker 		list_syscalls();
403*387f9dfdSAndroid Build Coastguard Worker 		goto free_names;
404*387f9dfdSAndroid Build Coastguard Worker 	}
405*387f9dfdSAndroid Build Coastguard Worker 
406*387f9dfdSAndroid Build Coastguard Worker 	libbpf_set_print(libbpf_print_fn);
407*387f9dfdSAndroid Build Coastguard Worker 
408*387f9dfdSAndroid Build Coastguard Worker 	err = ensure_core_btf(&open_opts);
409*387f9dfdSAndroid Build Coastguard Worker 	if (err) {
410*387f9dfdSAndroid Build Coastguard Worker 		fprintf(stderr, "failed to fetch necessary BTF for CO-RE: %s\n", strerror(-err));
411*387f9dfdSAndroid Build Coastguard Worker 		return 1;
412*387f9dfdSAndroid Build Coastguard Worker 	}
413*387f9dfdSAndroid Build Coastguard Worker 
414*387f9dfdSAndroid Build Coastguard Worker 	obj = syscount_bpf__open_opts(&open_opts);
415*387f9dfdSAndroid Build Coastguard Worker 	if (!obj) {
416*387f9dfdSAndroid Build Coastguard Worker 		warn("failed to open BPF object\n");
417*387f9dfdSAndroid Build Coastguard Worker 		err = 1;
418*387f9dfdSAndroid Build Coastguard Worker 		goto free_names;
419*387f9dfdSAndroid Build Coastguard Worker 	}
420*387f9dfdSAndroid Build Coastguard Worker 
421*387f9dfdSAndroid Build Coastguard Worker 	if (env.pid)
422*387f9dfdSAndroid Build Coastguard Worker 		obj->rodata->filter_pid = env.pid;
423*387f9dfdSAndroid Build Coastguard Worker 	if (env.failures)
424*387f9dfdSAndroid Build Coastguard Worker 		obj->rodata->filter_failed = true;
425*387f9dfdSAndroid Build Coastguard Worker 	if (env.latency)
426*387f9dfdSAndroid Build Coastguard Worker 		obj->rodata->measure_latency = true;
427*387f9dfdSAndroid Build Coastguard Worker 	if (env.process)
428*387f9dfdSAndroid Build Coastguard Worker 		obj->rodata->count_by_process = true;
429*387f9dfdSAndroid Build Coastguard Worker 	if (env.filter_errno)
430*387f9dfdSAndroid Build Coastguard Worker 		obj->rodata->filter_errno = env.filter_errno;
431*387f9dfdSAndroid Build Coastguard Worker 	if (env.cg)
432*387f9dfdSAndroid Build Coastguard Worker 		obj->rodata->filter_cg = env.cg;
433*387f9dfdSAndroid Build Coastguard Worker 
434*387f9dfdSAndroid Build Coastguard Worker 	err = syscount_bpf__load(obj);
435*387f9dfdSAndroid Build Coastguard Worker 	if (err) {
436*387f9dfdSAndroid Build Coastguard Worker 		warn("failed to load BPF object: %s\n", strerror(-err));
437*387f9dfdSAndroid Build Coastguard Worker 		goto cleanup_obj;
438*387f9dfdSAndroid Build Coastguard Worker 	}
439*387f9dfdSAndroid Build Coastguard Worker 
440*387f9dfdSAndroid Build Coastguard Worker 	/* update cgroup path fd to map */
441*387f9dfdSAndroid Build Coastguard Worker 	if (env.cg) {
442*387f9dfdSAndroid Build Coastguard Worker 		idx = 0;
443*387f9dfdSAndroid Build Coastguard Worker 		cg_map_fd = bpf_map__fd(obj->maps.cgroup_map);
444*387f9dfdSAndroid Build Coastguard Worker 		cgfd = open(env.cgroupspath, O_RDONLY);
445*387f9dfdSAndroid Build Coastguard Worker 		if (cgfd < 0) {
446*387f9dfdSAndroid Build Coastguard Worker 			fprintf(stderr, "Failed opening Cgroup path: %s", env.cgroupspath);
447*387f9dfdSAndroid Build Coastguard Worker 			goto cleanup_obj;
448*387f9dfdSAndroid Build Coastguard Worker 		}
449*387f9dfdSAndroid Build Coastguard Worker 		if (bpf_map_update_elem(cg_map_fd, &idx, &cgfd, BPF_ANY)) {
450*387f9dfdSAndroid Build Coastguard Worker 			fprintf(stderr, "Failed adding target cgroup to map");
451*387f9dfdSAndroid Build Coastguard Worker 			goto cleanup_obj;
452*387f9dfdSAndroid Build Coastguard Worker 		}
453*387f9dfdSAndroid Build Coastguard Worker 	}
454*387f9dfdSAndroid Build Coastguard Worker 
455*387f9dfdSAndroid Build Coastguard Worker 	obj->links.sys_exit = bpf_program__attach(obj->progs.sys_exit);
456*387f9dfdSAndroid Build Coastguard Worker 	if (!obj->links.sys_exit) {
457*387f9dfdSAndroid Build Coastguard Worker 		err = -errno;
458*387f9dfdSAndroid Build Coastguard Worker 		warn("failed to attach sys_exit program: %s\n", strerror(-err));
459*387f9dfdSAndroid Build Coastguard Worker 		goto cleanup_obj;
460*387f9dfdSAndroid Build Coastguard Worker 	}
461*387f9dfdSAndroid Build Coastguard Worker 	if (env.latency) {
462*387f9dfdSAndroid Build Coastguard Worker 		obj->links.sys_enter = bpf_program__attach(obj->progs.sys_enter);
463*387f9dfdSAndroid Build Coastguard Worker 		if (!obj->links.sys_enter) {
464*387f9dfdSAndroid Build Coastguard Worker 			err = -errno;
465*387f9dfdSAndroid Build Coastguard Worker 			warn("failed to attach sys_enter programs: %s\n",
466*387f9dfdSAndroid Build Coastguard Worker 			     strerror(-err));
467*387f9dfdSAndroid Build Coastguard Worker 			goto cleanup_obj;
468*387f9dfdSAndroid Build Coastguard Worker 		}
469*387f9dfdSAndroid Build Coastguard Worker 	}
470*387f9dfdSAndroid Build Coastguard Worker 
471*387f9dfdSAndroid Build Coastguard Worker 	if (signal(SIGINT, sig_int) == SIG_ERR) {
472*387f9dfdSAndroid Build Coastguard Worker 		warn("can't set signal handler: %s\n", strerror(errno));
473*387f9dfdSAndroid Build Coastguard Worker 		goto cleanup_obj;
474*387f9dfdSAndroid Build Coastguard Worker 	}
475*387f9dfdSAndroid Build Coastguard Worker 
476*387f9dfdSAndroid Build Coastguard Worker 	compar = env.latency ? compar_latency : compar_count;
477*387f9dfdSAndroid Build Coastguard Worker 	print = env.latency ? print_latency : print_count;
478*387f9dfdSAndroid Build Coastguard Worker 
479*387f9dfdSAndroid Build Coastguard Worker 	printf("Tracing syscalls, printing top %d... Ctrl+C to quit.\n", env.top);
480*387f9dfdSAndroid Build Coastguard Worker 	while (hang_on) {
481*387f9dfdSAndroid Build Coastguard Worker 		sleep(env.interval ?: 1);
482*387f9dfdSAndroid Build Coastguard Worker 		if (env.duration) {
483*387f9dfdSAndroid Build Coastguard Worker 			seconds += env.interval ?: 1;
484*387f9dfdSAndroid Build Coastguard Worker 			if (seconds >= env.duration)
485*387f9dfdSAndroid Build Coastguard Worker 				hang_on = 0;
486*387f9dfdSAndroid Build Coastguard Worker 		}
487*387f9dfdSAndroid Build Coastguard Worker 		if (hang_on && !env.interval)
488*387f9dfdSAndroid Build Coastguard Worker 			continue;
489*387f9dfdSAndroid Build Coastguard Worker 
490*387f9dfdSAndroid Build Coastguard Worker 		count = MAX_ENTRIES;
491*387f9dfdSAndroid Build Coastguard Worker 		if (!read_vals(bpf_map__fd(obj->maps.data), vals, &count))
492*387f9dfdSAndroid Build Coastguard Worker 			break;
493*387f9dfdSAndroid Build Coastguard Worker 		if (!count)
494*387f9dfdSAndroid Build Coastguard Worker 			continue;
495*387f9dfdSAndroid Build Coastguard Worker 
496*387f9dfdSAndroid Build Coastguard Worker 		qsort(vals, count, sizeof(vals[0]), compar);
497*387f9dfdSAndroid Build Coastguard Worker 		print_timestamp();
498*387f9dfdSAndroid Build Coastguard Worker 		print(vals, count);
499*387f9dfdSAndroid Build Coastguard Worker 	}
500*387f9dfdSAndroid Build Coastguard Worker 
501*387f9dfdSAndroid Build Coastguard Worker cleanup_obj:
502*387f9dfdSAndroid Build Coastguard Worker 	syscount_bpf__destroy(obj);
503*387f9dfdSAndroid Build Coastguard Worker free_names:
504*387f9dfdSAndroid Build Coastguard Worker 	free_syscall_names();
505*387f9dfdSAndroid Build Coastguard Worker 	cleanup_core_btf(&open_opts);
506*387f9dfdSAndroid Build Coastguard Worker 	if (cgfd > 0)
507*387f9dfdSAndroid Build Coastguard Worker 		close(cgfd);
508*387f9dfdSAndroid Build Coastguard Worker 
509*387f9dfdSAndroid Build Coastguard Worker 	return err != 0;
510*387f9dfdSAndroid Build Coastguard Worker }
511