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 (strcmp(argname, func->args[i].name) != 0)
319 continue;
320 p_debug("setting base arg for val %s to %d", val->name, i);
321 val->base_arg = i;
322
323 if (strlen(membername) > 0) {
324 if (member_to_value(btf, membername,
325 func->args[i].type_id, val, 0))
326 return -ENOENT;
327 } else {
328 val->type_id = func->args[i].type_id;
329 val->flags |= func->args[i].flags;
330 val->size = func->args[i].size;
331 }
332 return predicate_to_value(predicate, val);
333 }
334 p_err("Could not find '%s' in arguments/return value for '%s'",
335 argname, func->name);
336 return -ENOENT;
337 }
338
get_btf(const char * name)339 static struct btf *get_btf(const char *name)
340 {
341 struct btf *mod_btf;
342 int err;
343
344 p_debug("getting BTF for %s",
345 name && strlen(name) > 0 ? name : "vmlinux");
346
347 if (!vmlinux_btf) {
348 vmlinux_btf = btf__load_vmlinux_btf();
349 if (!vmlinux_btf) {
350 err = -errno;
351 p_err("No BTF, cannot determine type info: %s", strerror(-err));
352 return NULL;
353 }
354 }
355 if (!name || strlen(name) == 0)
356 return vmlinux_btf;
357
358 mod_btf = btf__load_module_btf(name, vmlinux_btf);
359 if (!mod_btf) {
360 err = -errno;
361 p_err("No BTF for module '%s': %s", name, strerror(-err));
362 return NULL;
363 }
364 return mod_btf;
365 }
366
copy_without_spaces(char * target,char * src)367 static void copy_without_spaces(char *target, char *src)
368 {
369 for (; *src != '\0'; src++)
370 if (!isspace(*src))
371 *(target++) = *src;
372 *target = '\0';
373 }
374
type_id_to_str(struct btf * btf,__s32 type_id,char * str)375 static char *type_id_to_str(struct btf *btf, __s32 type_id, char *str)
376 {
377 const struct btf_type *type;
378 const char *name = "";
379 char *prefix = "";
380 char *suffix = " ";
381 char *ptr = "";
382
383 str[0] = '\0';
384
385 switch (type_id) {
386 case 0:
387 name = "void";
388 break;
389 case KSNOOP_ID_UNKNOWN:
390 name = "?";
391 break;
392 default:
393 do {
394 type = btf__type_by_id(btf, type_id);
395 if (!type) {
396 name = "?";
397 break;
398 }
399
400 switch (BTF_INFO_KIND(type->info)) {
401 case BTF_KIND_CONST:
402 case BTF_KIND_VOLATILE:
403 case BTF_KIND_RESTRICT:
404 type_id = type->type;
405 break;
406 case BTF_KIND_PTR:
407 ptr = "* ";
408 type_id = type->type;
409 break;
410 case BTF_KIND_ARRAY:
411 suffix = "[]";
412 type_id = type->type;
413 break;
414 case BTF_KIND_STRUCT:
415 prefix = "struct ";
416 name = btf__str_by_offset(btf, type->name_off);
417 break;
418 case BTF_KIND_UNION:
419 prefix = "union ";
420 name = btf__str_by_offset(btf, type->name_off);
421 break;
422 case BTF_KIND_ENUM:
423 prefix = "enum ";
424 name = btf__str_by_offset(btf, type->name_off);
425 break;
426 case BTF_KIND_TYPEDEF:
427 name = btf__str_by_offset(btf, type->name_off);
428 break;
429 default:
430 name = btf__str_by_offset(btf, type->name_off);
431 break;
432 }
433 } while (type_id >= 0 && strlen(name) == 0);
434 break;
435 }
436 snprintf(str, MAX_STR, "%s%s%s%s", prefix, name, suffix, ptr);
437
438 return str;
439 }
440
value_to_str(struct btf * btf,struct value * val,char * str)441 static char *value_to_str(struct btf *btf, struct value *val, char *str)
442 {
443
444 str = type_id_to_str(btf, val->type_id, str);
445 if (val->flags & KSNOOP_F_PTR)
446 strncat(str, "*", MAX_STR);
447 if (strlen(val->name) > 0 &&
448 strcmp(val->name, KSNOOP_RETURN_NAME) != 0)
449 strncat(str, val->name, MAX_STR);
450
451 return str;
452 }
453
454 /* based heavily on bpf_object__read_kallsyms_file() in libbpf.c */
get_func_ip_mod(struct func * func)455 static int get_func_ip_mod(struct func *func)
456 {
457 char sym_type, sym_name[MAX_STR], mod_info[MAX_STR];
458 unsigned long long sym_addr;
459 int ret, err = 0;
460 FILE *f;
461
462 f = fopen("/proc/kallsyms", "r");
463 if (!f) {
464 err = errno;
465 p_err("failed to open /proc/kallsyms: %s", strerror(err));
466 return err;
467 }
468
469 while (true) {
470 ret = fscanf(f, "%llx %c %128s%[^\n]\n",
471 &sym_addr, &sym_type, sym_name, mod_info);
472 if (ret == EOF && feof(f))
473 break;
474 if (ret < 3) {
475 p_err("failed to read kallsyms entry: %d", ret);
476 err = -EINVAL;
477 goto out;
478 }
479 if (strcmp(func->name, sym_name) != 0)
480 continue;
481 func->ip = sym_addr;
482 func->mod[0] = '\0';
483 /* get module name from [modname] */
484 if (ret == 4) {
485 if (sscanf(mod_info, "%*[\t ][%[^]]", func->mod) < 1) {
486 p_err("failed to read module name");
487 err = -EINVAL;
488 goto out;
489 }
490 }
491 p_debug("%s = <ip %llx, mod %s>", func->name, func->ip,
492 strlen(func->mod) > 0 ? func->mod : "vmlinux");
493 break;
494 }
495 out:
496 fclose(f);
497 return err;
498 }
499
trace_printf(void * ctx,const char * fmt,va_list args)500 static void trace_printf(void *ctx, const char *fmt, va_list args)
501 {
502 vprintf(fmt, args);
503 }
504
505 #define VALID_NAME "%[A-Za-z0-9\\-_]"
506 #define ARGDATA "%[^)]"
507
parse_trace(char * str,struct trace * trace)508 static int parse_trace(char *str, struct trace *trace)
509 {
510 __u8 i, nr_predicates = 0, nr_entry = 0, nr_return = 0;
511 char argname[MAX_NAME], membername[MAX_NAME];
512 char tracestr[MAX_STR], argdata[MAX_STR];
513 struct func *func = &trace->func;
514 char *arg, *saveptr;
515 int ret;
516
517 copy_without_spaces(tracestr, str);
518
519 p_debug("Parsing trace '%s'", tracestr);
520
521 trace->filter_pid = (__u32)filter_pid;
522 if (filter_pid)
523 p_debug("Using pid %lu as filter", trace->filter_pid);
524
525 trace->btf = vmlinux_btf;
526
527 ret = sscanf(tracestr, VALID_NAME "(" ARGDATA ")", func->name, argdata);
528 if (ret <= 0)
529 usage();
530 if (ret == 1) {
531 if (strlen(tracestr) > strlen(func->name)) {
532 p_err("Invalid function specification '%s'", tracestr);
533 usage();
534 }
535 argdata[0] = '\0';
536 p_debug("got func '%s'", func->name);
537 } else {
538 if (strlen(tracestr) >
539 strlen(func->name) + strlen(argdata) + 2) {
540 p_err("Invalid function specification '%s'", tracestr);
541 usage();
542 }
543 p_debug("got func '%s', args '%s'", func->name, argdata);
544 trace->flags |= KSNOOP_F_CUSTOM;
545 }
546
547 ret = get_func_ip_mod(func);
548 if (ret) {
549 p_err("could not get address of '%s'", func->name);
550 return ret;
551 }
552 trace->btf = get_btf(func->mod);
553 if (!trace->btf) {
554 ret = -errno;
555 p_err("could not get BTF for '%s': %s",
556 strlen(func->mod) ? func->mod : "vmlinux",
557 strerror(-ret));
558 return -ENOENT;
559 }
560 trace->dump = btf_dump__new(trace->btf, trace_printf, NULL, NULL);
561 if (!trace->dump) {
562 ret = -errno;
563 p_err("could not create BTF dump : %s", strerror(-ret));
564 return -EINVAL;
565 }
566
567 ret = get_func_btf(trace->btf, func);
568 if (ret) {
569 p_debug("unexpected return value '%d' getting function", ret);
570 return ret;
571 }
572
573 for (arg = strtok_r(argdata, ",", &saveptr), i = 0;
574 arg;
575 arg = strtok_r(NULL, ",", &saveptr), i++) {
576 char *predicate = NULL;
577
578 ret = sscanf(arg, VALID_NAME "->" VALID_NAME,
579 argname, membername);
580 if (ret == 2) {
581 if (strlen(arg) >
582 strlen(argname) + strlen(membername) + 2) {
583 predicate = arg + strlen(argname) +
584 strlen(membername) + 2;
585 }
586 p_debug("'%s' dereferences '%s', predicate '%s'",
587 argname, membername, predicate);
588 } else {
589 if (strlen(arg) > strlen(argname))
590 predicate = arg + strlen(argname);
591 p_debug("'%s' arg, predcate '%s'", argname, predicate);
592 membername[0] = '\0';
593 }
594
595 if (i >= MAX_TRACES) {
596 p_err("Too many arguments; up to %d are supported",
597 MAX_TRACES);
598 return -EINVAL;
599 }
600 if (trace_to_value(trace->btf, func, argname, membername,
601 predicate, &trace->traces[i]))
602 return -EINVAL;
603
604 if (predicate)
605 nr_predicates++;
606 if (trace->traces[i].base_arg == KSNOOP_RETURN)
607 nr_return++;
608 else
609 nr_entry++;
610 trace->nr_traces++;
611 }
612
613 if (trace->nr_traces > 0) {
614 trace->flags |= KSNOOP_F_CUSTOM;
615 p_debug("custom trace with %d args", trace->nr_traces);
616
617 /* If we have one or more predicates _and_ references to
618 * entry and return values, we need to activate "stash"
619 * mode where arg traces are stored on entry and not
620 * sent until return to ensure predicates are satisfied.
621 */
622 if (nr_predicates > 0 && nr_entry > 0 && nr_return > 0) {
623 trace->flags |= KSNOOP_F_STASH;
624 p_debug("activating stash mode on entry");
625 }
626 } else {
627 p_debug("Standard trace, function with %d arguments",
628 func->nr_args);
629 /* copy function arg/return value to trace specification. */
630 memcpy(trace->traces, func->args, sizeof(trace->traces));
631 for (i = 0; i < MAX_TRACES; i++)
632 trace->traces[i].base_arg = i;
633 trace->nr_traces = MAX_TRACES;
634 }
635
636 return 0;
637 }
638
parse_traces(int argc,char ** argv,struct trace ** traces)639 static int parse_traces(int argc, char **argv, struct trace **traces)
640 {
641 __u8 i;
642
643 if (argc == 0)
644 usage();
645
646 if (argc > MAX_FUNC_TRACES) {
647 p_err("A maximum of %d traces are supported", MAX_FUNC_TRACES);
648 return -EINVAL;
649 }
650 *traces = calloc(argc, sizeof(struct trace));
651 if (!*traces) {
652 p_err("Could not allocate %d traces", argc);
653 return -ENOMEM;
654 }
655 for (i = 0; i < argc; i++) {
656 if (parse_trace(argv[i], &((*traces)[i])))
657 return -EINVAL;
658 if (!stack_mode || i == 0)
659 continue;
660 /* tell stack mode trace which function to expect next */
661 (*traces)[i].prev_ip = (*traces)[i-1].func.ip;
662 (*traces)[i-1].next_ip = (*traces)[i].func.ip;
663 }
664 return i;
665 }
666
cmd_info(int argc,char ** argv)667 static int cmd_info(int argc, char **argv)
668 {
669 struct trace *traces = NULL;
670 char str[MAX_STR];
671 int nr_traces;
672 __u8 i, j;
673
674 nr_traces = parse_traces(argc, argv, &traces);
675 if (nr_traces < 0)
676 return nr_traces;
677
678 for (i = 0; i < nr_traces; i++) {
679 struct func *func = &traces[i].func;
680
681 printf("%s%s(",
682 value_to_str(traces[i].btf, &func->args[KSNOOP_RETURN],
683 str),
684 func->name);
685 for (j = 0; j < func->nr_args; j++) {
686 if (j > 0)
687 printf(", ");
688 printf("%s", value_to_str(traces[i].btf, &func->args[j],
689 str));
690 }
691 if (func->nr_args > MAX_ARGS)
692 printf(" /* and %d more args that are not traceable */",
693 func->nr_args - MAX_ARGS);
694 printf(");\n");
695 }
696 free(traces);
697 return 0;
698 }
699
trace_handler(void * ctx,int cpu,void * data,__u32 size)700 static void trace_handler(void *ctx, int cpu, void *data, __u32 size)
701 {
702 struct trace *trace = data;
703 int i, shown, ret;
704
705 p_debug("got trace, size %d", size);
706 if (size < (sizeof(*trace) - MAX_TRACE_BUF)) {
707 p_err("\t/* trace buffer size '%u' < min %ld */",
708 size, sizeof(trace) - MAX_TRACE_BUF);
709 return;
710 }
711 printf("%16lld %4d %8u %s(\n", trace->time, trace->cpu, trace->pid,
712 trace->func.name);
713
714 for (i = 0, shown = 0; i < trace->nr_traces; i++) {
715 DECLARE_LIBBPF_OPTS(btf_dump_type_data_opts, opts);
716 bool entry = trace->data_flags & KSNOOP_F_ENTRY;
717 struct value *val = &trace->traces[i];
718 struct trace_data *data = &trace->trace_data[i];
719
720 opts.indent_level = 36;
721 opts.indent_str = " ";
722
723 /* skip if it's entry data and trace data is for return, or
724 * if it's return and trace data is entry; only exception in
725 * the latter case is if we stashed data; in such cases we
726 * want to see it as it's a mix of entry/return data with
727 * predicates.
728 */
729 if ((entry && !base_arg_is_entry(val->base_arg)) ||
730 (!entry && base_arg_is_entry(val->base_arg) &&
731 !(trace->flags & KSNOOP_F_STASH)))
732 continue;
733
734 if (val->type_id == 0)
735 continue;
736
737 if (shown > 0)
738 printf(",\n");
739 printf("%34s %s = ", "", val->name);
740 if (val->flags & KSNOOP_F_PTR)
741 printf("*(0x%llx)", data->raw_value);
742 printf("\n");
743
744 if (data->err_type_id != 0) {
745 char typestr[MAX_STR];
746
747 printf("%36s /* Cannot show '%s' as '%s%s'; invalid/userspace ptr? */\n",
748 "",
749 val->name,
750 type_id_to_str(trace->btf,
751 val->type_id,
752 typestr),
753 val->flags & KSNOOP_F_PTR ?
754 " *" : "");
755 } else {
756 ret = btf_dump__dump_type_data
757 (trace->dump, val->type_id,
758 trace->buf + data->buf_offset,
759 data->buf_len, &opts);
760 /* truncated? */
761 if (ret == -E2BIG)
762 printf("%36s... /* %d bytes of %d */", "",
763 data->buf_len,
764 val->size);
765 }
766 shown++;
767
768 }
769 printf("\n%31s);\n\n", "");
770 fflush(stdout);
771 }
772
lost_handler(void * ctx,int cpu,__u64 cnt)773 static void lost_handler(void *ctx, int cpu, __u64 cnt)
774 {
775 p_err("\t/* lost %llu events */", cnt);
776 }
777
sig_int(int signo)778 static void sig_int(int signo)
779 {
780 exiting = 1;
781 }
782
add_traces(struct bpf_map * func_map,struct trace * traces,int nr_traces)783 static int add_traces(struct bpf_map *func_map, struct trace *traces,
784 int nr_traces)
785 {
786 int i, j, ret, nr_cpus = libbpf_num_possible_cpus();
787 struct trace *map_traces;
788
789 map_traces = calloc(nr_cpus, sizeof(struct trace));
790 if (!map_traces) {
791 p_err("Could not allocate memory for %d traces", nr_traces);
792 return -ENOMEM;
793 }
794 for (i = 0; i < nr_traces; i++) {
795 for (j = 0; j < nr_cpus; j++)
796 memcpy(&map_traces[j], &traces[i],
797 sizeof(map_traces[j]));
798
799 ret = bpf_map_update_elem(bpf_map__fd(func_map),
800 &traces[i].func.ip,
801 map_traces,
802 BPF_NOEXIST);
803 if (ret) {
804 p_err("Could not add map entry for '%s': %s",
805 traces[i].func.name, strerror(-ret));
806 break;
807 }
808 }
809 free(map_traces);
810 return ret;
811 }
812
attach_traces(struct ksnoop_bpf * skel,struct trace * traces,int nr_traces)813 static int attach_traces(struct ksnoop_bpf *skel, struct trace *traces,
814 int nr_traces)
815 {
816 int i, ret;
817
818 for (i = 0; i < nr_traces; i++) {
819 traces[i].links[0] =
820 bpf_program__attach_kprobe(skel->progs.kprobe_entry,
821 false,
822 traces[i].func.name);
823 if (!traces[i].links[0]) {
824 ret = -errno;
825 p_err("Could not attach kprobe to '%s': %s",
826 traces[i].func.name, strerror(-ret));
827 return ret;
828 }
829 p_debug("Attached kprobe for '%s'", traces[i].func.name);
830
831 traces[i].links[1] =
832 bpf_program__attach_kprobe(skel->progs.kprobe_return,
833 true,
834 traces[i].func.name);
835 if (!traces[i].links[1]) {
836 ret = -errno;
837 p_err("Could not attach kretprobe to '%s': %s",
838 traces[i].func.name, strerror(-ret));
839 return ret;
840 }
841 p_debug("Attached kretprobe for '%s'", traces[i].func.name);
842 }
843 return 0;
844 }
845
cmd_trace(int argc,char ** argv)846 static int cmd_trace(int argc, char **argv)
847 {
848 struct bpf_map *perf_map, *func_map;
849 struct perf_buffer *pb = NULL;
850 struct ksnoop_bpf *skel;
851 int i, nr_traces, ret = -1;
852 struct trace *traces = NULL;
853
854 nr_traces = parse_traces(argc, argv, &traces);
855 if (nr_traces < 0)
856 return nr_traces;
857
858 skel = ksnoop_bpf__open_and_load();
859 if (!skel) {
860 ret = -errno;
861 p_err("Could not load ksnoop BPF: %s", strerror(-ret));
862 return 1;
863 }
864
865 perf_map = skel->maps.ksnoop_perf_map;
866 if (!perf_map) {
867 p_err("Could not find '%s'", "ksnoop_perf_map");
868 goto cleanup;
869 }
870 func_map = bpf_object__find_map_by_name(skel->obj, "ksnoop_func_map");
871 if (!func_map) {
872 p_err("Could not find '%s'", "ksnoop_func_map");
873 goto cleanup;
874 }
875
876 if (add_traces(func_map, traces, nr_traces)) {
877 p_err("Could not add traces to '%s'", "ksnoop_func_map");
878 goto cleanup;
879 }
880
881 if (attach_traces(skel, traces, nr_traces)) {
882 p_err("Could not attach %d traces", nr_traces);
883 goto cleanup;
884 }
885
886 pb = perf_buffer__new(bpf_map__fd(perf_map), pages,
887 trace_handler, lost_handler, NULL, NULL);
888 if (!pb) {
889 ret = -errno;
890 p_err("Could not create perf buffer: %s", strerror(-ret));
891 goto cleanup;
892 }
893
894 printf("%16s %4s %8s %s\n", "TIME", "CPU", "PID", "FUNCTION/ARGS");
895
896 if (signal(SIGINT, sig_int) == SIG_ERR) {
897 fprintf(stderr, "can't set signal handler: %s\n", strerror(errno));
898 ret = 1;
899 goto cleanup;
900 }
901
902 while (!exiting) {
903 ret = perf_buffer__poll(pb, 1);
904 if (ret < 0 && ret != -EINTR) {
905 fprintf(stderr, "error polling perf buffer: %s\n", strerror(-ret));
906 goto cleanup;
907 }
908 /* reset ret to return 0 if exiting */
909 ret = 0;
910 }
911
912 cleanup:
913 for (i = 0; i < nr_traces; i++) {
914 bpf_link__destroy(traces[i].links[0]);
915 bpf_link__destroy(traces[i].links[1]);
916 }
917 free(traces);
918 perf_buffer__free(pb);
919 ksnoop_bpf__destroy(skel);
920
921 return ret;
922 }
923
924 struct cmd {
925 const char *cmd;
926 int (*func)(int argc, char **argv);
927 };
928
929 struct cmd cmds[] = {
930 { "info", cmd_info },
931 { "trace", cmd_trace },
932 { "help", cmd_help },
933 { NULL, NULL }
934 };
935
cmd_select(int argc,char ** argv)936 static int cmd_select(int argc, char **argv)
937 {
938 int i;
939
940 for (i = 0; cmds[i].cmd; i++) {
941 if (strncmp(*argv, cmds[i].cmd, strlen(*argv)) == 0)
942 return cmds[i].func(argc - 1, argv + 1);
943 }
944 return cmd_trace(argc, argv);
945 }
946
libbpf_print_fn(enum libbpf_print_level level,const char * format,va_list args)947 static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
948 {
949 if (level == LIBBPF_DEBUG && !verbose)
950 return 0;
951 return vfprintf(stderr, format, args);
952 }
953
main(int argc,char * argv[])954 int main(int argc, char *argv[])
955 {
956 static const struct option options[] = {
957 { "debug", no_argument, NULL, 'd' },
958 { "verbose", no_argument, NULL, 'v' },
959 { "help", no_argument, NULL, 'h' },
960 { "version", no_argument, NULL, 'V' },
961 { "pages", required_argument, NULL, 'P' },
962 { "pid", required_argument, NULL, 'p' },
963 { 0 }
964 };
965 int opt;
966
967 bin_name = argv[0];
968
969 while ((opt = getopt_long(argc, argv, "dvhp:P:sV", options,
970 NULL)) >= 0) {
971 switch (opt) {
972 case 'd':
973 verbose = true;
974 log_level = DEBUG;
975 break;
976 case 'v':
977 verbose = true;
978 log_level = DEBUG;
979 break;
980 case 'h':
981 return cmd_help(argc, argv);
982 case 'V':
983 return do_version(argc, argv);
984 case 'p':
985 filter_pid = atoi(optarg);
986 break;
987 case 'P':
988 pages = atoi(optarg);
989 break;
990 case 's':
991 stack_mode = true;
992 break;
993 default:
994 p_err("unrecognized option '%s'", argv[optind - 1]);
995 usage();
996 }
997 }
998 if (argc == 1)
999 usage();
1000 argc -= optind;
1001 argv += optind;
1002 if (argc < 0)
1003 usage();
1004
1005 libbpf_set_print(libbpf_print_fn);
1006
1007 return cmd_select(argc, argv);
1008 }
1009