• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 /* Copyright (c) 2021, Oracle and/or its affiliates. */
3 
4 #include <ctype.h>
5 #include <errno.h>
6 #include <getopt.h>
7 #include <signal.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include <bpf/bpf.h>
13 #include <bpf/libbpf.h>
14 #include <bpf/btf.h>
15 
16 #include "ksnoop.h"
17 #include "ksnoop.skel.h"
18 
19 #ifndef KSNOOP_VERSION
20 #define KSNOOP_VERSION	"0.1"
21 #endif
22 
23 static volatile sig_atomic_t exiting = 0;
24 
25 static struct btf *vmlinux_btf;
26 static const char *bin_name;
27 static int pages = PAGES_DEFAULT;
28 
29 enum log_level {
30 	DEBUG,
31 	WARN,
32 	ERROR,
33 };
34 
35 static enum log_level log_level = WARN;
36 static bool verbose = false;
37 
38 static __u32 filter_pid;
39 static bool stack_mode;
40 
41 
__p(enum log_level level,char * level_str,char * fmt,...)42 static void __p(enum log_level level, char *level_str, char *fmt, ...)
43 {
44 	va_list ap;
45 
46 	if (level < log_level)
47 		return;
48 	va_start(ap, fmt);
49 	fprintf(stderr, "%s: ", level_str);
50 	vfprintf(stderr, fmt, ap);
51 	fprintf(stderr, "\n");
52 	va_end(ap);
53 	fflush(stderr);
54 }
55 
56 #define p_err(fmt, ...)		__p(ERROR, "Error", fmt, ##__VA_ARGS__)
57 #define p_warn(fmt, ...)	__p(WARNING, "Warn", fmt, ##__VA_ARGS__)
58 #define	p_debug(fmt, ...)	__p(DEBUG, "Debug", fmt, ##__VA_ARGS__)
59 
do_version(int argc,char ** argv)60 static int do_version(int argc, char **argv)
61 {
62 	printf("%s v%s\n", bin_name, KSNOOP_VERSION);
63 	return 0;
64 }
65 
cmd_help(int argc,char ** argv)66 static int cmd_help(int argc, char **argv)
67 {
68 	fprintf(stderr,
69 		"Usage: %s [OPTIONS] [COMMAND | help] FUNC\n"
70 		"	COMMAND	:= { trace | info }\n"
71 		"	FUNC	:= { name | name(ARG[,ARG]*) }\n"
72 		"	ARG	:= { arg | arg [PRED] | arg->member [PRED] }\n"
73 		"	PRED	:= { == | != | > | >= | < | <=  value }\n"
74 		"	OPTIONS	:= { {-d|--debug} | {-v|--verbose} | {-V|--version} |\n"
75 		"                    {-p|--pid filter_pid}|\n"
76 		"                    {-P|--pages nr_pages} }\n"
77 		"                    {-s|--stack}\n",
78 		bin_name);
79 	fprintf(stderr,
80 		"Examples:\n"
81 		"	%s info ip_send_skb\n"
82 		"	%s trace ip_send_skb\n"
83 		"	%s trace \"ip_send_skb(skb, return)\"\n"
84 		"	%s trace \"ip_send_skb(skb->sk, return)\"\n"
85 		"	%s trace \"ip_send_skb(skb->len > 128, skb)\"\n"
86 		"	%s trace -s udp_sendmsg ip_send_skb\n",
87 		bin_name, bin_name, bin_name, bin_name, bin_name, bin_name);
88 	return 0;
89 }
90 
usage(void)91 static void usage(void)
92 {
93 	cmd_help(0, NULL);
94 	exit(1);
95 }
96 
type_to_value(struct btf * btf,char * name,__u32 type_id,struct value * val)97 static void type_to_value(struct btf *btf, char *name, __u32 type_id,
98 			  struct value *val)
99 {
100 	const struct btf_type *type;
101 	__s32 id = type_id;
102 
103 	if (strlen(val->name) == 0) {
104 		if (name)
105 			strncpy(val->name, name,
106 				sizeof(val->name) - 1);
107 		else
108 			val->name[0] = '\0';
109 	}
110 	do {
111 		type = btf__type_by_id(btf, id);
112 
113 		switch (BTF_INFO_KIND(type->info)) {
114 		case BTF_KIND_CONST:
115 		case BTF_KIND_VOLATILE:
116 		case BTF_KIND_RESTRICT:
117 			id = type->type;
118 			break;
119 		case BTF_KIND_PTR:
120 			val->flags |= KSNOOP_F_PTR;
121 			id = type->type;
122 			break;
123 		default:
124 			val->type_id = id;
125 			goto done;
126 		}
127 	} while (id >= 0);
128 
129 	val->type_id = KSNOOP_ID_UNKNOWN;
130 	return;
131 done:
132 	val->size = btf__resolve_size(btf, val->type_id);
133 }
134 
member_to_value(struct btf * btf,const char * name,__u32 type_id,struct value * val,int lvl)135 static int member_to_value(struct btf *btf, const char *name, __u32 type_id,
136 			   struct value *val, int lvl)
137 {
138 	const struct btf_member *member;
139 	const struct btf_type *type;
140 	const char *pname;
141 	__s32 id = type_id;
142 	int i, nmembers;
143 	__u8 kind;
144 
145 	/* type_to_value has already stripped qualifiers, so
146 	 * we either have a base type, a struct, union, etc.
147 	 * Only struct/unions have named members so anything
148 	 * else is invalid.
149 	 */
150 	p_debug("Looking for member '%s' in type id %d", name, type_id);
151 	type = btf__type_by_id(btf, id);
152 	pname = btf__str_by_offset(btf, type->name_off);
153 	if (strlen(pname) == 0)
154 		pname = "<anon>";
155 
156 	kind = BTF_INFO_KIND(type->info);
157 	switch (kind) {
158 	case BTF_KIND_STRUCT:
159 	case BTF_KIND_UNION:
160 		nmembers = BTF_INFO_VLEN(type->info);
161 		p_debug("Checking %d members...", nmembers);
162 		for (member = (struct btf_member *)(type + 1), i = 0;
163 		     i < nmembers;
164 		     member++, i++) {
165 			const char *mname;
166 			__u16 offset;
167 
168 			type = btf__type_by_id(btf, member->type);
169 			mname = btf__str_by_offset(btf, member->name_off);
170 			offset = member->offset / 8;
171 
172 			p_debug("Checking member '%s' type %d offset %d",
173 				mname, member->type, offset);
174 
175 			/* anonymous struct member? */
176 			kind = BTF_INFO_KIND(type->info);
177 			if (strlen(mname) == 0 &&
178 			    (kind == BTF_KIND_STRUCT ||
179 			     kind == BTF_KIND_UNION)) {
180 				p_debug("Checking anon struct/union %d",
181 					member->type);
182 				val->offset += offset;
183 				if (!member_to_value(btf, name, member->type,
184 						     val, lvl + 1))
185 					return 0;
186 				val->offset -= offset;
187 				continue;
188 			}
189 
190 			if (strcmp(mname, name) == 0) {
191 				val->offset += offset;
192 				val->flags |= KSNOOP_F_MEMBER;
193 				type_to_value(btf, NULL, member->type, val);
194 				p_debug("Member '%s', offset %d, flags %x size %d",
195 					mname, val->offset, val->flags,
196 					val->size);
197 				return 0;
198 			}
199 		}
200 		if (lvl > 0)
201 			break;
202 		p_err("No member '%s' found in %s [%d], offset %d", name, pname,
203 		      id, val->offset);
204 		break;
205 	default:
206 		p_err("'%s' is not a struct/union", pname);
207 		break;
208 	}
209 	return -ENOENT;
210 }
211 
get_func_btf(struct btf * btf,struct func * func)212 static int get_func_btf(struct btf *btf, struct func *func)
213 {
214 	const struct btf_param *param;
215 	const struct btf_type *type;
216 	__u8 i;
217 
218 	func->id = btf__find_by_name_kind(btf, func->name, BTF_KIND_FUNC);
219 	if (func->id <= 0) {
220 		p_err("Cannot find function '%s' in BTF: %s",
221 		       func->name, strerror(-func->id));
222 		return -ENOENT;
223 	}
224 	type = btf__type_by_id(btf, func->id);
225 	if (!type || BTF_INFO_KIND(type->info) != BTF_KIND_FUNC) {
226 		p_err("Error looking up function type via id '%d'", func->id);
227 		return -EINVAL;
228 	}
229 	type = btf__type_by_id(btf, type->type);
230 	if (!type || BTF_INFO_KIND(type->info) != BTF_KIND_FUNC_PROTO) {
231 		p_err("Error looking up function proto type via id '%d'",
232 		      func->id);
233 		return -EINVAL;
234 	}
235 	for (param = (struct btf_param *)(type + 1), i = 0;
236 	     i < BTF_INFO_VLEN(type->info) && i < MAX_ARGS;
237 	     param++, i++) {
238 		type_to_value(btf,
239 			      (char *)btf__str_by_offset(btf, param->name_off),
240 			      param->type, &func->args[i]);
241 		p_debug("arg #%d: <name '%s', type id '%u'>",
242 			i + 1, func->args[i].name, func->args[i].type_id);
243 	}
244 
245 	/* real number of args, even if it is > number we recorded. */
246 	func->nr_args = BTF_INFO_VLEN(type->info);
247 
248 	type_to_value(btf, KSNOOP_RETURN_NAME, type->type,
249 		      &func->args[KSNOOP_RETURN]);
250 	p_debug("return value: type id '%u'>",
251 		func->args[KSNOOP_RETURN].type_id);
252 	return 0;
253 }
254 
predicate_to_value(char * predicate,struct value * val)255 static int predicate_to_value(char *predicate, struct value *val)
256 {
257 	char pred[MAX_STR];
258 	long v;
259 
260 	if (!predicate)
261 		return 0;
262 
263 	p_debug("checking predicate '%s' for '%s'", predicate, val->name);
264 
265 	if (sscanf(predicate, "%[!=><]%li", pred, &v) != 2) {
266 		p_err("Invalid specification; expected predicate, not '%s'",
267 		      predicate);
268 		return -EINVAL;
269 	}
270 	if (!(val->flags & KSNOOP_F_PTR) &&
271 	    (val->size == 0 || val->size > sizeof(__u64))) {
272 		p_err("'%s' (size %d) does not support predicate comparison",
273 		      val->name, val->size);
274 		return -EINVAL;
275 	}
276 	val->predicate_value = (__u64)v;
277 
278 	if (strcmp(pred, "==") == 0) {
279 		val->flags |= KSNOOP_F_PREDICATE_EQ;
280 		goto out;
281 	} else if (strcmp(pred, "!=") == 0) {
282 		val->flags |= KSNOOP_F_PREDICATE_NOTEQ;
283 		goto out;
284 	}
285 	if (pred[0] == '>')
286 		val->flags |= KSNOOP_F_PREDICATE_GT;
287 	else if (pred[0] == '<')
288 		val->flags |= KSNOOP_F_PREDICATE_LT;
289 
290 	if (strlen(pred) == 1)
291 		goto out;
292 
293 	if (pred[1] != '=') {
294 		p_err("Invalid predicate specification '%s'", predicate);
295 		return -EINVAL;
296 	}
297 	val->flags |= KSNOOP_F_PREDICATE_EQ;
298 
299 out:
300 	p_debug("predicate '%s', flags 0x%x value %x",
301 		pred, val->flags, val->predicate_value);
302 
303 	return 0;
304 }
305 
trace_to_value(struct btf * btf,struct func * func,char * argname,char * membername,char * predicate,struct value * val)306 static int trace_to_value(struct btf *btf, struct func *func, char *argname,
307 			  char *membername, char *predicate, struct value *val)
308 {
309 	__u8 i;
310 
311 	if (strlen(membername) > 0)
312 		snprintf(val->name, sizeof(val->name), "%s->%s",
313 			 argname, membername);
314 	else
315 		strncpy(val->name, argname, sizeof(val->name));
316 
317 	for (i = 0; i < MAX_TRACES; i++) {
318 		if (!func->args[i].name)
319 			continue;
320 		if (strcmp(argname, func->args[i].name) != 0)
321 			continue;
322 		p_debug("setting base arg for val %s to %d", val->name, i);
323 		val->base_arg = i;
324 
325 		if (strlen(membername) > 0) {
326 			if (member_to_value(btf, membername,
327 					    func->args[i].type_id, val, 0))
328 				return -ENOENT;
329 		} else {
330 			val->type_id = func->args[i].type_id;
331 			val->flags |= func->args[i].flags;
332 			val->size = func->args[i].size;
333 		}
334 		return predicate_to_value(predicate, val);
335 	}
336 	p_err("Could not find '%s' in arguments/return value for '%s'",
337 	      argname, func->name);
338 	return -ENOENT;
339 }
340 
get_btf(const char * name)341 static struct btf *get_btf(const char *name)
342 {
343 	struct btf *mod_btf;
344 	int err;
345 
346 	p_debug("getting BTF for %s",
347 		name && strlen(name) > 0 ? name : "vmlinux");
348 
349 	if (!vmlinux_btf) {
350 		vmlinux_btf = btf__load_vmlinux_btf();
351 		if (!vmlinux_btf) {
352 			err = -errno;
353 			p_err("No BTF, cannot determine type info: %s", strerror(-err));
354 			return NULL;
355 		}
356 	}
357 	if (!name || strlen(name) == 0)
358 		return vmlinux_btf;
359 
360 	mod_btf = btf__load_module_btf(name, vmlinux_btf);
361 	if (!mod_btf) {
362 		err = -errno;
363 		p_err("No BTF for module '%s': %s", name, strerror(-err));
364 		return NULL;
365 	}
366 	return mod_btf;
367 }
368 
copy_without_spaces(char * target,char * src)369 static void copy_without_spaces(char *target, char *src)
370 {
371 	for (; *src != '\0'; src++)
372 		if (!isspace(*src))
373 			*(target++) = *src;
374 	*target = '\0';
375 }
376 
type_id_to_str(struct btf * btf,__s32 type_id,char * str)377 static char *type_id_to_str(struct btf *btf, __s32 type_id, char *str)
378 {
379 	const struct btf_type *type;
380 	const char *name = "";
381 	char *prefix = "";
382 	char *suffix = " ";
383 	char *ptr = "";
384 
385 	str[0] = '\0';
386 
387 	switch (type_id) {
388 	case 0:
389 		name = "void";
390 		break;
391 	case KSNOOP_ID_UNKNOWN:
392 		name = "?";
393 		break;
394 	default:
395 		do {
396 			type = btf__type_by_id(btf, type_id);
397 			if (!type) {
398 				name = "?";
399 				break;
400 			}
401 
402 			switch (BTF_INFO_KIND(type->info)) {
403 			case BTF_KIND_CONST:
404 			case BTF_KIND_VOLATILE:
405 			case BTF_KIND_RESTRICT:
406 				type_id = type->type;
407 				break;
408 			case BTF_KIND_PTR:
409 				ptr = "* ";
410 				type_id = type->type;
411 				break;
412 			case BTF_KIND_ARRAY:
413 				suffix = "[]";
414 				type_id = type->type;
415 				break;
416 			case BTF_KIND_STRUCT:
417 				prefix = "struct ";
418 				name = btf__str_by_offset(btf, type->name_off);
419 				break;
420 			case BTF_KIND_UNION:
421 				prefix = "union ";
422 				name = btf__str_by_offset(btf, type->name_off);
423 				break;
424 			case BTF_KIND_ENUM:
425 				prefix = "enum ";
426 				name = btf__str_by_offset(btf, type->name_off);
427 				break;
428 			case BTF_KIND_TYPEDEF:
429 				name = btf__str_by_offset(btf, type->name_off);
430 				break;
431 			default:
432 				name = btf__str_by_offset(btf, type->name_off);
433 				break;
434 			}
435 		} while (type_id >= 0 && strlen(name) == 0);
436 		break;
437 	}
438 	snprintf(str, MAX_STR, "%s%s%s%s", prefix, name, suffix, ptr);
439 
440 	return str;
441 }
442 
value_to_str(struct btf * btf,struct value * val,char * str)443 static char *value_to_str(struct btf *btf, struct value *val, char *str)
444 {
445 
446 	str = type_id_to_str(btf, val->type_id, str);
447 	if (val->flags & KSNOOP_F_PTR)
448 		strncat(str, "*", MAX_STR);
449 	if (strlen(val->name) > 0 &&
450 	    strcmp(val->name, KSNOOP_RETURN_NAME) != 0)
451 		strncat(str, val->name, MAX_STR);
452 
453 	return str;
454 }
455 
456 /* based heavily on bpf_object__read_kallsyms_file() in libbpf.c */
get_func_ip_mod(struct func * func)457 static int get_func_ip_mod(struct func *func)
458 {
459 	char sym_type, sym_name[MAX_STR], mod_info[MAX_STR];
460 	unsigned long long sym_addr;
461 	int ret, err = 0;
462 	FILE *f;
463 
464 	f = fopen("/proc/kallsyms", "r");
465 	if (!f) {
466 		err = errno;
467 		p_err("failed to open /proc/kallsyms: %d", strerror(err));
468 		return err;
469 	}
470 
471 	while (true) {
472 		ret = fscanf(f, "%llx %c %128s%[^\n]\n",
473 			     &sym_addr, &sym_type, sym_name, mod_info);
474 		if (ret == EOF && feof(f))
475 			break;
476 		if (ret < 3) {
477 			p_err("failed to read kallsyms entry: %d", ret);
478 			err = -EINVAL;
479 			goto out;
480 		}
481 		if (strcmp(func->name, sym_name) != 0)
482 			continue;
483 		func->ip = sym_addr;
484 		func->mod[0] = '\0';
485 		/* get module name from [modname] */
486 		if (ret == 4) {
487 			if (sscanf(mod_info, "%*[\t ][%[^]]", func->mod) < 1) {
488 				p_err("failed to read module name");
489 				err = -EINVAL;
490 				goto out;
491 			}
492 		}
493 		p_debug("%s =  <ip %llx, mod %s>", func->name, func->ip,
494 			strlen(func->mod) > 0 ? func->mod : "vmlinux");
495 		break;
496 	}
497 out:
498 	fclose(f);
499 	return err;
500 }
501 
trace_printf(void * ctx,const char * fmt,va_list args)502 static void trace_printf(void *ctx, const char *fmt, va_list args)
503 {
504 	vprintf(fmt, args);
505 }
506 
507 #define VALID_NAME	"%[A-Za-z0-9\\-_]"
508 #define ARGDATA		"%[^)]"
509 
parse_trace(char * str,struct trace * trace)510 static int parse_trace(char *str, struct trace *trace)
511 {
512 	__u8 i, nr_predicates = 0, nr_entry = 0, nr_return = 0;
513 	char argname[MAX_NAME], membername[MAX_NAME];
514 	char tracestr[MAX_STR], argdata[MAX_STR];
515 	struct func *func = &trace->func;
516 	struct btf_dump_opts opts = { };
517 	char *arg, *saveptr;
518 	int ret;
519 
520 	copy_without_spaces(tracestr, str);
521 
522 	p_debug("Parsing trace '%s'", tracestr);
523 
524 	trace->filter_pid = (__u32)filter_pid;
525 	if (filter_pid)
526 		p_debug("Using pid %lu as filter", trace->filter_pid);
527 
528 	trace->btf = vmlinux_btf;
529 
530 	ret = sscanf(tracestr, VALID_NAME "(" ARGDATA ")", func->name, argdata);
531 	if (ret <= 0)
532 		usage();
533 	if (ret == 1) {
534 		if (strlen(tracestr) > strlen(func->name)) {
535 			p_err("Invalid function specification '%s'", tracestr);
536 			usage();
537 		}
538 		argdata[0] = '\0';
539 		p_debug("got func '%s'", func->name);
540 	} else {
541 		if (strlen(tracestr) >
542 		    strlen(func->name) + strlen(argdata) + 2) {
543 			p_err("Invalid function specification '%s'", tracestr);
544 			usage();
545 		}
546 		p_debug("got func '%s', args '%s'", func->name, argdata);
547 		trace->flags |= KSNOOP_F_CUSTOM;
548 	}
549 
550 	ret = get_func_ip_mod(func);
551 	if (ret) {
552 		p_err("could not get address of '%s'", func->name);
553 		return ret;
554 	}
555 	trace->btf = get_btf(func->mod);
556 	if (!trace->btf) {
557 		ret = -errno;
558 		p_err("could not get BTF for '%s': %s",
559 		      strlen(func->mod) ? func->mod : "vmlinux",
560 		      strerror(-ret));
561 		return -ENOENT;
562 	}
563 	trace->dump = btf_dump__new(trace->btf, NULL, &opts, trace_printf);
564 	if (!trace->dump) {
565 		ret = -errno;
566 		p_err("could not create BTF dump : %n", strerror(-ret));
567 		return -EINVAL;
568 	}
569 
570 	ret = get_func_btf(trace->btf, func);
571 	if (ret) {
572 		p_debug("unexpected return value '%d' getting function", ret);
573 		return ret;
574 	}
575 
576 	for (arg = strtok_r(argdata, ",", &saveptr), i = 0;
577 	     arg;
578 	     arg = strtok_r(NULL, ",", &saveptr), i++) {
579 		char *predicate = NULL;
580 
581 		ret = sscanf(arg, VALID_NAME "->" VALID_NAME,
582 			     argname, membername);
583 		if (ret == 2) {
584 			if (strlen(arg) >
585 			    strlen(argname) + strlen(membername) + 2) {
586 				predicate = arg + strlen(argname) +
587 					    strlen(membername) + 2;
588 			}
589 			p_debug("'%s' dereferences '%s', predicate '%s'",
590 				argname, membername, predicate);
591 		} else {
592 			if (strlen(arg) > strlen(argname))
593 				predicate = arg + strlen(argname);
594 			p_debug("'%s' arg, predcate '%s'", argname, predicate);
595 			membername[0] = '\0';
596 		}
597 
598 		if (i >= MAX_TRACES) {
599 			p_err("Too many arguments; up to %d are supported",
600 			      MAX_TRACES);
601 			return -EINVAL;
602 		}
603 		if (trace_to_value(trace->btf, func, argname, membername,
604 				   predicate, &trace->traces[i]))
605 			return -EINVAL;
606 
607 		if (predicate)
608 			nr_predicates++;
609 		if (trace->traces[i].base_arg == KSNOOP_RETURN)
610 			nr_return++;
611 		else
612 			nr_entry++;
613 		trace->nr_traces++;
614 	}
615 
616 	if (trace->nr_traces > 0) {
617 		trace->flags |= KSNOOP_F_CUSTOM;
618 		p_debug("custom trace with %d args", trace->nr_traces);
619 
620 		/* If we have one or more predicates _and_ references to
621 		 * entry and return values, we need to activate "stash"
622 		 * mode where arg traces are stored on entry and not
623 		 * sent until return to ensure predicates are satisfied.
624 		 */
625 		if (nr_predicates > 0 && nr_entry > 0 && nr_return > 0) {
626 			trace->flags |= KSNOOP_F_STASH;
627 			p_debug("activating stash mode on entry");
628 		}
629 	} else {
630 		p_debug("Standard trace, function with %d arguments",
631 			func->nr_args);
632 		/* copy function arg/return value to trace specification. */
633 		memcpy(trace->traces, func->args, sizeof(trace->traces));
634 		for (i = 0; i < MAX_TRACES; i++)
635 			trace->traces[i].base_arg = i;
636 		trace->nr_traces = MAX_TRACES;
637 	}
638 
639 	return 0;
640 }
641 
parse_traces(int argc,char ** argv,struct trace ** traces)642 static int parse_traces(int argc, char **argv, struct trace **traces)
643 {
644 	__u8 i;
645 
646 	if (argc == 0)
647 		usage();
648 
649 	if (argc > MAX_FUNC_TRACES) {
650 		p_err("A maximum of %d traces are supported", MAX_FUNC_TRACES);
651 		return -EINVAL;
652 	}
653 	*traces = calloc(argc, sizeof(struct trace));
654 	if (!*traces) {
655 		p_err("Could not allocate %d traces", argc);
656 		return -ENOMEM;
657 	}
658 	for (i = 0; i < argc; i++) {
659 		if (parse_trace(argv[i], &((*traces)[i])))
660 			return -EINVAL;
661 		if (!stack_mode || i == 0)
662 			continue;
663 		/* tell stack mode trace which function to expect next */
664 		(*traces)[i].prev_ip = (*traces)[i-1].func.ip;
665 		(*traces)[i-1].next_ip = (*traces)[i].func.ip;
666 	}
667 	return i;
668 }
669 
cmd_info(int argc,char ** argv)670 static int cmd_info(int argc, char **argv)
671 {
672 	struct trace *traces = NULL;
673 	char str[MAX_STR];
674 	int nr_traces;
675 	__u8 i, j;
676 
677 	nr_traces = parse_traces(argc, argv, &traces);
678 	if (nr_traces < 0)
679 		return nr_traces;
680 
681 	for (i = 0; i < nr_traces; i++) {
682 		struct func *func = &traces[i].func;
683 
684 		printf("%s%s(",
685 		       value_to_str(traces[i].btf, &func->args[KSNOOP_RETURN],
686 				    str),
687 		       func->name);
688 		for (j = 0; j < func->nr_args; j++) {
689 			if (j > 0)
690 				printf(", ");
691 			printf("%s", value_to_str(traces[i].btf, &func->args[j],
692 						  str));
693 		}
694 		if (func->nr_args > MAX_ARGS)
695 			printf(" /* and %d more args that are not traceable */",
696 			       func->nr_args - MAX_ARGS);
697 		printf(");\n");
698 	}
699 	free(traces);
700 	return 0;
701 }
702 
trace_handler(void * ctx,int cpu,void * data,__u32 size)703 static void trace_handler(void *ctx, int cpu, void *data, __u32 size)
704 {
705 	struct trace *trace = data;
706 	int i, shown, ret;
707 
708 	p_debug("got trace, size %d", size);
709 	if (size < (sizeof(*trace) - MAX_TRACE_BUF)) {
710 		p_err("\t/* trace buffer size '%u' < min %ld */",
711 			size, sizeof(trace) - MAX_TRACE_BUF);
712 		return;
713 	}
714 	printf("%16lld %4d %8u %s(\n", trace->time, trace->cpu, trace->pid,
715 	       trace->func.name);
716 
717 	for (i = 0, shown = 0; i < trace->nr_traces; i++) {
718 		DECLARE_LIBBPF_OPTS(btf_dump_type_data_opts, opts);
719 		bool entry = trace->data_flags & KSNOOP_F_ENTRY;
720 		struct value *val = &trace->traces[i];
721 		struct trace_data *data = &trace->trace_data[i];
722 
723 		opts.indent_level = 36;
724 		opts.indent_str = " ";
725 
726 		/* skip if it's entry data and trace data is for return, or
727 		 * if it's return and trace data is entry; only exception in
728 		 * the latter case is if we stashed data; in such cases we
729 		 * want to see it as it's a mix of entry/return data with
730 		 * predicates.
731  		 */
732 		if ((entry && !base_arg_is_entry(val->base_arg)) ||
733 		    (!entry && base_arg_is_entry(val->base_arg) &&
734 		     !(trace->flags & KSNOOP_F_STASH)))
735 			continue;
736 
737 		if (val->type_id == 0)
738 			continue;
739 
740 		if (shown > 0)
741 			printf(",\n");
742 		printf("%34s %s = ", "", val->name);
743 		if (val->flags & KSNOOP_F_PTR)
744 			printf("*(0x%llx)", data->raw_value);
745 		printf("\n");
746 
747 		if (data->err_type_id != 0) {
748 			char typestr[MAX_STR];
749 
750 			printf("%36s /* Cannot show '%s' as '%s%s'; invalid/userspace ptr? */\n",
751 			       "",
752 			       val->name,
753 			       type_id_to_str(trace->btf,
754 					      val->type_id,
755 					      typestr),
756 			       val->flags & KSNOOP_F_PTR ?
757 			       " *" : "");
758 		} else {
759 			ret = btf_dump__dump_type_data
760 				(trace->dump, val->type_id,
761 				 trace->buf + data->buf_offset,
762 				 data->buf_len, &opts);
763 			/* truncated? */
764 			if (ret == -E2BIG)
765 				printf("%36s... /* %d bytes of %d */", "",
766 				       data->buf_len,
767 				       val->size);
768 		}
769 		shown++;
770 
771 	}
772 	printf("\n%31s);\n\n", "");
773 	fflush(stdout);
774 }
775 
lost_handler(void * ctx,int cpu,__u64 cnt)776 static void lost_handler(void *ctx, int cpu, __u64 cnt)
777 {
778 	p_err("\t/* lost %llu events */", cnt);
779 }
780 
sig_int(int signo)781 static void sig_int(int signo)
782 {
783 	exiting = 1;
784 }
785 
add_traces(struct bpf_map * func_map,struct trace * traces,int nr_traces)786 static int add_traces(struct bpf_map *func_map, struct trace *traces,
787 		      int nr_traces)
788 {
789 	int i, j, ret, nr_cpus = libbpf_num_possible_cpus();
790 	struct trace *map_traces;
791 
792 	map_traces = calloc(nr_cpus, sizeof(struct trace));
793 	if (!map_traces) {
794 		p_err("Could not allocate memory for %d traces", nr_traces);
795 		return -ENOMEM;
796 	}
797 	for (i = 0; i < nr_traces; i++) {
798 		for (j = 0; j < nr_cpus; j++)
799 			memcpy(&map_traces[j], &traces[i],
800 			       sizeof(map_traces[j]));
801 
802 		ret = bpf_map_update_elem(bpf_map__fd(func_map),
803 					  &traces[i].func.ip,
804 					  map_traces,
805 					  BPF_NOEXIST);
806 		if (ret) {
807 			p_err("Could not add map entry for '%s': %s",
808 			      traces[i].func.name, strerror(-ret));
809 			break;
810 		}
811 	}
812 	free(map_traces);
813 	return ret;
814 }
815 
attach_traces(struct ksnoop_bpf * skel,struct trace * traces,int nr_traces)816 static int attach_traces(struct ksnoop_bpf *skel, struct trace *traces,
817 			 int nr_traces)
818 {
819 	int i, ret;
820 
821 	for (i = 0; i < nr_traces; i++) {
822 		traces[i].links[0] =
823 			bpf_program__attach_kprobe(skel->progs.kprobe_entry,
824 						   false,
825 						   traces[i].func.name);
826 		if (!traces[i].links[0]) {
827 			ret = -errno;
828 			p_err("Could not attach kprobe to '%s': %s",
829 			      traces[i].func.name, strerror(-ret));
830 				return ret;
831 		}
832 		p_debug("Attached kprobe for '%s'", traces[i].func.name);
833 
834 		traces[i].links[1] =
835 			bpf_program__attach_kprobe(skel->progs.kprobe_return,
836 						   true,
837 						   traces[i].func.name);
838 		if (!traces[i].links[1]) {
839 			ret = -errno;
840 			p_err("Could not attach kretprobe to '%s': %s",
841 			      traces[i].func.name, strerror(-ret));
842 			return ret;
843 		}
844 		p_debug("Attached kretprobe for '%s'", traces[i].func.name);
845 	}
846 	return 0;
847 }
848 
cmd_trace(int argc,char ** argv)849 static int cmd_trace(int argc, char **argv)
850 {
851 	struct bpf_map *perf_map, *func_map;
852 	struct perf_buffer *pb = NULL;
853 	struct ksnoop_bpf *skel;
854 	int i, nr_traces, ret = -1;
855 	struct trace *traces = NULL;
856 
857 	nr_traces = parse_traces(argc, argv, &traces);
858 	if (nr_traces < 0)
859 		return nr_traces;
860 
861 	skel = ksnoop_bpf__open_and_load();
862 	if (!skel) {
863 		ret = -errno;
864 		p_err("Could not load ksnoop BPF: %s", strerror(-ret));
865 		return 1;
866 	}
867 
868 	perf_map = skel->maps.ksnoop_perf_map;
869 	if (!perf_map) {
870 		p_err("Could not find '%s'", "ksnoop_perf_map");
871 		goto cleanup;
872 	}
873 	func_map = bpf_object__find_map_by_name(skel->obj, "ksnoop_func_map");
874 	if (!func_map) {
875 		p_err("Could not find '%s'", "ksnoop_func_map");
876 		goto cleanup;
877 	}
878 
879 	if (add_traces(func_map, traces, nr_traces)) {
880 		p_err("Could not add traces to '%s'", "ksnoop_func_map");
881 		goto cleanup;
882 	}
883 
884 	if (attach_traces(skel, traces, nr_traces)) {
885 		p_err("Could not attach %d traces", nr_traces);
886 		goto cleanup;
887 	}
888 
889 	pb = perf_buffer__new(bpf_map__fd(perf_map), pages,
890 			      trace_handler, lost_handler, NULL, NULL);
891 	if (!pb) {
892 		ret = -errno;
893 		p_err("Could not create perf buffer: %s", strerror(-ret));
894 		goto cleanup;
895 	}
896 
897 	printf("%16s %4s %8s %s\n", "TIME", "CPU", "PID", "FUNCTION/ARGS");
898 
899 	if (signal(SIGINT, sig_int) == SIG_ERR) {
900 		fprintf(stderr, "can't set signal handler: %s\n", strerror(errno));
901 		ret = 1;
902 		goto cleanup;
903 	}
904 
905 	while (!exiting) {
906 		ret = perf_buffer__poll(pb, 1);
907 		if (ret < 0 && ret != -EINTR) {
908 			fprintf(stderr, "error polling perf buffer: %s\n", strerror(-ret));
909 			goto cleanup;
910 		}
911 		/* reset ret to return 0 if exiting */
912 		ret = 0;
913 	}
914 
915 cleanup:
916 	for (i = 0; i < nr_traces; i++) {
917 		bpf_link__destroy(traces[i].links[0]);
918 		bpf_link__destroy(traces[i].links[1]);
919 	}
920 	free(traces);
921 	perf_buffer__free(pb);
922 	ksnoop_bpf__destroy(skel);
923 
924 	return ret;
925 }
926 
927 struct cmd {
928 	const char *cmd;
929 	int (*func)(int argc, char **argv);
930 };
931 
932 struct cmd cmds[] = {
933 	{ "info",	cmd_info },
934 	{ "trace",	cmd_trace },
935 	{ "help",	cmd_help },
936 	{ NULL,		NULL }
937 };
938 
cmd_select(int argc,char ** argv)939 static int cmd_select(int argc, char **argv)
940 {
941 	int i;
942 
943 	for (i = 0; cmds[i].cmd; i++) {
944 		if (strncmp(*argv, cmds[i].cmd, strlen(*argv)) == 0)
945 			return cmds[i].func(argc - 1, argv + 1);
946 	}
947 	return cmd_trace(argc, argv);
948 }
949 
libbpf_print_fn(enum libbpf_print_level level,const char * format,va_list args)950 static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
951 {
952 	if (level == LIBBPF_DEBUG && !verbose)
953 		return 0;
954 	return vfprintf(stderr, format, args);
955 }
956 
main(int argc,char * argv[])957 int main(int argc, char *argv[])
958 {
959 	static const struct option options[] = {
960 		{ "debug",	no_argument,		NULL,	'd' },
961 		{ "verbose",	no_argument,		NULL,	'v' },
962 		{ "help",	no_argument,		NULL,	'h' },
963 		{ "version",	no_argument,		NULL,	'V' },
964 		{ "pages",	required_argument,	NULL,	'P' },
965 		{ "pid",	required_argument,	NULL,	'p' },
966 		{ 0 }
967 	};
968 	int opt;
969 
970 	bin_name = argv[0];
971 
972 	while ((opt = getopt_long(argc, argv, "dvhp:P:sV", options,
973 				  NULL)) >= 0) {
974 		switch (opt) {
975 		case 'd':
976 			verbose = true;
977 			log_level = DEBUG;
978 			break;
979 		case 'v':
980 			verbose = true;
981 			log_level = DEBUG;
982 			break;
983 		case 'h':
984 			return cmd_help(argc, argv);
985 		case 'V':
986 			return do_version(argc, argv);
987 		case 'p':
988 			filter_pid = atoi(optarg);
989 			break;
990 		case 'P':
991 			pages = atoi(optarg);
992 			break;
993 		case 's':
994 			stack_mode = true;
995 			break;
996 		default:
997 			p_err("unrecognized option '%s'", argv[optind - 1]);
998 			usage();
999 		}
1000 	}
1001 	if (argc == 1)
1002 		usage();
1003 	argc -= optind;
1004 	argv += optind;
1005 	if (argc < 0)
1006 		usage();
1007 
1008 	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
1009 	libbpf_set_print(libbpf_print_fn);
1010 
1011 	return cmd_select(argc, argv);
1012 }
1013