projects/linux·blob master · refs

5971 lines · 168.3 KiB

1/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <[email protected]>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 */
16
17#include "util/record.h"
18#include <api/fs/tracing_path.h>
19#ifdef HAVE_LIBBPF_SUPPORT
20#include <bpf/bpf.h>
21#include <bpf/libbpf.h>
22#include <bpf/btf.h>
23#endif
24#include "util/rlimit.h"
25#include "builtin.h"
26#include "util/cgroup.h"
27#include "util/color.h"
28#include "util/config.h"
29#include "util/debug.h"
30#include "util/dso.h"
31#include "util/env.h"
32#include "util/event.h"
33#include "util/evsel.h"
34#include "util/evsel_fprintf.h"
35#include "util/synthetic-events.h"
36#include "util/evlist.h"
37#include "util/evswitch.h"
38#include "util/hashmap.h"
39#include "util/mmap.h"
40#include <subcmd/pager.h>
41#include <subcmd/exec-cmd.h>
42#include "util/machine.h"
43#include "util/map.h"
44#include "util/symbol.h"
45#include "util/path.h"
46#include "util/session.h"
47#include "util/thread.h"
48#include <subcmd/parse-options.h>
49#include "util/strlist.h"
50#include "util/intlist.h"
51#include "util/thread_map.h"
52#include "util/stat.h"
53#include "util/tool.h"
54#include "util/trace.h"
55#include "util/util.h"
56#include "trace/beauty/beauty.h"
57#include "trace-event.h"
58#include "util/parse-events.h"
59#include "util/tracepoint.h"
60#include "callchain.h"
61#include "print_binary.h"
62#include "string2.h"
63#include "trace/beauty/syscalltbl.h"
64#include "../perf.h"
65#include "trace_augment.h"
66#include "dwarf-regs.h"
67
68#include <errno.h>
69#include <sys/stat.h>
70#include <inttypes.h>
71#include <poll.h>
72#include <signal.h>
73#include <stdlib.h>
74#include <string.h>
75#include <linux/err.h>
76#include <linux/filter.h>
77#include <linux/kernel.h>
78#include <linux/list_sort.h>
79#include <linux/random.h>
80#include <linux/stringify.h>
81#include <linux/time64.h>
82#include <linux/zalloc.h>
83#include <fcntl.h>
84#include <sys/sysmacros.h>
85
86#include <linux/ctype.h>
87#include <perf/mmap.h>
88#include <tools/libc_compat.h>
89
90#ifdef HAVE_LIBTRACEEVENT
91#include <event-parse.h>
92#endif
93
94#ifndef O_CLOEXEC
95# define O_CLOEXEC 02000000
96#endif
97
98#ifndef F_LINUX_SPECIFIC_BASE
99# define F_LINUX_SPECIFIC_BASE 1024
100#endif
101
102#define RAW_SYSCALL_ARGS_NUM 6
103
104/*
105 * strtoul: Go from a string to a value, i.e. for msr: MSR_FS_BASE to 0xc0000100
106 *
107 * We have to explicitely mark the direction of the flow of data, if from the
108 * kernel to user space or the other way around, since the BPF collector we
109 * have so far copies only from user to kernel space, mark the arguments that
110 * go that direction, so that we don´t end up collecting the previous contents
111 * for syscall args that goes from kernel to user space.
112 */
113struct syscall_arg_fmt {
114 size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
115 bool (*strtoul)(char *bf, size_t size, struct syscall_arg *arg, u64 *val);
116 unsigned long (*mask_val)(struct syscall_arg *arg, unsigned long val);
117 void *parm;
118 const char *name;
119 u16 nr_entries; // for arrays
120 bool from_user;
121 bool show_zero;
122#ifdef HAVE_LIBBPF_SUPPORT
123 const struct btf_type *type;
124 int type_id; /* used in btf_dump */
125#endif
126};
127
128struct syscall_fmt {
129 const char *name;
130 const char *alias;
131 struct {
132 const char *sys_enter,
133 *sys_exit;
134 } bpf_prog_name;
135 struct syscall_arg_fmt arg[RAW_SYSCALL_ARGS_NUM];
136 u8 nr_args;
137 bool errpid;
138 bool timeout;
139 bool hexret;
140};
141
142struct trace {
143 struct perf_env host_env;
144 struct perf_tool tool;
145 struct {
146 /** Sorted sycall numbers used by the trace. */
147 struct syscall **table;
148 /** Size of table. */
149 size_t table_size;
150 struct {
151 struct evsel *sys_enter,
152 *sys_exit,
153 *bpf_output;
154 } events;
155 } syscalls;
156#ifdef HAVE_LIBBPF_SUPPORT
157 struct btf *btf;
158#endif
159 struct record_opts opts;
160 struct evlist *evlist;
161 struct machine *host;
162 struct thread *current;
163 struct cgroup *cgroup;
164 u64 base_time;
165 FILE *output;
166 unsigned long nr_events;
167 unsigned long nr_events_printed;
168 unsigned long max_events;
169 struct evswitch evswitch;
170 struct strlist *ev_qualifier;
171 struct {
172 size_t nr;
173 int *entries;
174 } ev_qualifier_ids;
175 struct {
176 size_t nr;
177 pid_t *entries;
178 struct bpf_map *map;
179 } filter_pids;
180 /*
181 * TODO: The map is from an ID (aka system call number) to struct
182 * syscall_stats. If there is >1 e_machine, such as i386 and x86-64
183 * processes, then the stats here will gather wrong the statistics for
184 * the non EM_HOST system calls. A fix would be to add the e_machine
185 * into the key, but this would make the code inconsistent with the
186 * per-thread version.
187 */
188 struct hashmap *syscall_stats;
189 double duration_filter;
190 double runtime_ms;
191 unsigned long pfmaj, pfmin;
192 struct {
193 u64 vfs_getname,
194 proc_getname;
195 } stats;
196 unsigned int max_stack;
197 unsigned int min_stack;
198 enum trace_summary_mode summary_mode;
199 int max_summary;
200 int raw_augmented_syscalls_args_size;
201 bool raw_augmented_syscalls;
202 bool fd_path_disabled;
203 bool sort_events;
204 bool not_ev_qualifier;
205 bool live;
206 bool full_time;
207 bool sched;
208 bool multiple_threads;
209 bool summary;
210 bool summary_only;
211 bool errno_summary;
212 bool failure_only;
213 bool show_comm;
214 bool print_sample;
215 bool show_tool_stats;
216 bool trace_syscalls;
217 bool libtraceevent_print;
218 bool kernel_syscallchains;
219 s16 args_alignment;
220 bool show_tstamp;
221 bool show_cpu;
222 bool show_duration;
223 bool show_zeros;
224 bool show_arg_names;
225 bool show_string_prefix;
226 bool force;
227 bool vfs_getname;
228 bool force_btf;
229 bool bitmask_list;
230 bool summary_bpf;
231 int trace_pgfaults;
232 char *perfconfig_events;
233 struct {
234 struct ordered_events data;
235 u64 last;
236 } oe;
237 const char *uid_str;
238};
239
240bool trace__show_zeros(const struct trace *trace)
241{
242 return trace->show_zeros;
243}
244
245struct machine *trace__host(const struct trace *trace)
246{
247 return trace->host;
248}
249
250static void trace__load_vmlinux_btf(struct trace *trace __maybe_unused)
251{
252#ifdef HAVE_LIBBPF_SUPPORT
253 if (trace->btf != NULL)
254 return;
255
256 trace->btf = btf__load_vmlinux_btf();
257 if (verbose > 0) {
258 fprintf(trace->output, trace->btf ? "vmlinux BTF loaded\n" :
259 "Failed to load vmlinux BTF\n");
260 }
261#endif
262}
263
264struct tp_field {
265 int offset;
266 union {
267 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
268 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
269 };
270};
271
272#define TP_UINT_FIELD(bits) \
273static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
274{ \
275 u##bits value; \
276 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
277 return value; \
278}
279
280TP_UINT_FIELD(8);
281TP_UINT_FIELD(16);
282TP_UINT_FIELD(32);
283TP_UINT_FIELD(64);
284
285#define TP_UINT_FIELD__SWAPPED(bits) \
286static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
287{ \
288 u##bits value; \
289 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
290 return bswap_##bits(value);\
291}
292
293TP_UINT_FIELD__SWAPPED(16);
294TP_UINT_FIELD__SWAPPED(32);
295TP_UINT_FIELD__SWAPPED(64);
296
297static int __tp_field__init_uint(struct tp_field *field, int size, int offset, bool needs_swap)
298{
299 field->offset = offset;
300
301 switch (size) {
302 case 1:
303 field->integer = tp_field__u8;
304 break;
305 case 2:
306 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
307 break;
308 case 4:
309 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
310 break;
311 case 8:
312 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
313 break;
314 default:
315 return -1;
316 }
317
318 return 0;
319}
320
321static int tp_field__init_uint(struct tp_field *field, struct tep_format_field *format_field, bool needs_swap)
322{
323 return __tp_field__init_uint(field, format_field->size, format_field->offset, needs_swap);
324}
325
326static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
327{
328 return sample->raw_data + field->offset;
329}
330
331static int __tp_field__init_ptr(struct tp_field *field, int offset)
332{
333 field->offset = offset;
334 field->pointer = tp_field__ptr;
335 return 0;
336}
337
338static int tp_field__init_ptr(struct tp_field *field, struct tep_format_field *format_field)
339{
340 return __tp_field__init_ptr(field, format_field->offset);
341}
342
343struct syscall_tp {
344 struct tp_field id;
345 union {
346 struct tp_field args, ret;
347 };
348};
349
350/*
351 * The evsel->priv as used by 'perf trace'
352 * sc: for raw_syscalls:sys_{enter,exit} and syscalls:sys_{enter,exit}_SYSCALLNAME
353 * fmt: for all the other tracepoints
354 */
355struct evsel_trace {
356 struct syscall_tp sc;
357 struct syscall_arg_fmt *fmt;
358};
359
360static struct evsel_trace *evsel_trace__new(void)
361{
362 return zalloc(sizeof(struct evsel_trace));
363}
364
365static void evsel_trace__delete(struct evsel_trace *et)
366{
367 if (et == NULL)
368 return;
369
370 zfree(&et->fmt);
371 free(et);
372}
373
374/*
375 * Used with raw_syscalls:sys_{enter,exit} and with the
376 * syscalls:sys_{enter,exit}_SYSCALL tracepoints
377 */
378static inline struct syscall_tp *__evsel__syscall_tp(struct evsel *evsel)
379{
380 struct evsel_trace *et = evsel->priv;
381
382 return &et->sc;
383}
384
385static struct syscall_tp *evsel__syscall_tp(struct evsel *evsel)
386{
387 if (evsel->priv == NULL) {
388 evsel->priv = evsel_trace__new();
389 if (evsel->priv == NULL)
390 return NULL;
391 }
392
393 return __evsel__syscall_tp(evsel);
394}
395
396/*
397 * Used with all the other tracepoints.
398 */
399static inline struct syscall_arg_fmt *__evsel__syscall_arg_fmt(struct evsel *evsel)
400{
401 struct evsel_trace *et = evsel->priv;
402
403 return et->fmt;
404}
405
406static struct syscall_arg_fmt *evsel__syscall_arg_fmt(struct evsel *evsel)
407{
408 struct evsel_trace *et = evsel->priv;
409
410 if (evsel->priv == NULL) {
411 et = evsel->priv = evsel_trace__new();
412
413 if (et == NULL)
414 return NULL;
415 }
416
417 if (et->fmt == NULL) {
418 const struct tep_event *tp_format = evsel__tp_format(evsel);
419
420 if (tp_format == NULL)
421 goto out_delete;
422
423 et->fmt = calloc(tp_format->format.nr_fields, sizeof(struct syscall_arg_fmt));
424 if (et->fmt == NULL)
425 goto out_delete;
426 }
427
428 return __evsel__syscall_arg_fmt(evsel);
429
430out_delete:
431 evsel_trace__delete(evsel->priv);
432 evsel->priv = NULL;
433 return NULL;
434}
435
436static int evsel__init_tp_uint_field(struct evsel *evsel, struct tp_field *field, const char *name)
437{
438 struct tep_format_field *format_field = evsel__field(evsel, name);
439
440 if (format_field == NULL)
441 return -1;
442
443 return tp_field__init_uint(field, format_field, evsel->needs_swap);
444}
445
446#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
447 ({ struct syscall_tp *sc = __evsel__syscall_tp(evsel);\
448 evsel__init_tp_uint_field(evsel, &sc->name, #name); })
449
450static int evsel__init_tp_ptr_field(struct evsel *evsel, struct tp_field *field, const char *name)
451{
452 struct tep_format_field *format_field = evsel__field(evsel, name);
453
454 if (format_field == NULL)
455 return -1;
456
457 return tp_field__init_ptr(field, format_field);
458}
459
460#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
461 ({ struct syscall_tp *sc = __evsel__syscall_tp(evsel);\
462 evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
463
464static void evsel__put_and_free_priv(struct evsel *evsel)
465{
466 zfree(&evsel->priv);
467 evsel__put(evsel);
468}
469
470static int evsel__init_syscall_tp(struct evsel *evsel)
471{
472 struct syscall_tp *sc = evsel__syscall_tp(evsel);
473
474 if (sc != NULL) {
475 if (evsel__init_tp_uint_field(evsel, &sc->id, "__syscall_nr") &&
476 evsel__init_tp_uint_field(evsel, &sc->id, "nr"))
477 return -ENOENT;
478
479 return 0;
480 }
481
482 return -ENOMEM;
483}
484
485static int evsel__init_augmented_syscall_tp(struct evsel *evsel, struct evsel *tp)
486{
487 struct syscall_tp *sc = evsel__syscall_tp(evsel);
488
489 if (sc != NULL) {
490 struct tep_format_field *syscall_id = evsel__field(tp, "id");
491 if (syscall_id == NULL)
492 syscall_id = evsel__field(tp, "__syscall_nr");
493 if (syscall_id == NULL ||
494 __tp_field__init_uint(&sc->id, syscall_id->size, syscall_id->offset, evsel->needs_swap))
495 return -EINVAL;
496
497 return 0;
498 }
499
500 return -ENOMEM;
501}
502
503static int evsel__init_augmented_syscall_tp_args(struct evsel *evsel)
504{
505 struct syscall_tp *sc = __evsel__syscall_tp(evsel);
506
507 return __tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64));
508}
509
510static int evsel__init_augmented_syscall_tp_ret(struct evsel *evsel)
511{
512 struct syscall_tp *sc = __evsel__syscall_tp(evsel);
513
514 return __tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap);
515}
516
517static int evsel__init_raw_syscall_tp(struct evsel *evsel, void *handler)
518{
519 if (evsel__syscall_tp(evsel) != NULL) {
520 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
521 return -ENOENT;
522
523 evsel->handler = handler;
524 return 0;
525 }
526
527 return -ENOMEM;
528}
529
530static struct evsel *perf_evsel__raw_syscall_newtp(const char *direction, void *handler)
531{
532 struct evsel *evsel = evsel__newtp("raw_syscalls", direction);
533
534 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
535 if (IS_ERR(evsel))
536 evsel = evsel__newtp("syscalls", direction);
537
538 if (IS_ERR(evsel))
539 return NULL;
540
541 if (evsel__init_raw_syscall_tp(evsel, handler))
542 goto out_delete;
543
544 return evsel;
545
546out_delete:
547 evsel__put_and_free_priv(evsel);
548 return NULL;
549}
550
551#define perf_evsel__sc_tp_uint(name, sample) \
552 ({ struct syscall_tp *fields = __evsel__syscall_tp(sample->evsel); \
553 fields->name.integer(&fields->name, sample); })
554
555#define perf_evsel__sc_tp_ptr(name, sample) \
556 ({ struct syscall_tp *fields = __evsel__syscall_tp(sample->evsel); \
557 fields->name.pointer(&fields->name, sample); })
558
559size_t strarray__scnprintf_suffix(struct strarray *sa, char *bf, size_t size, const char *intfmt, bool show_suffix, int val)
560{
561 int idx = val - sa->offset;
562
563 if (idx < 0 || idx >= sa->nr_entries || sa->entries[idx] == NULL) {
564 size_t printed = scnprintf(bf, size, intfmt, val);
565 if (show_suffix)
566 printed += scnprintf(bf + printed, size - printed, " /* %s??? */", sa->prefix);
567 return printed;
568 }
569
570 return scnprintf(bf, size, "%s%s", sa->entries[idx], show_suffix ? sa->prefix : "");
571}
572
573size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, bool show_prefix, int val)
574{
575 int idx = val - sa->offset;
576
577 if (idx < 0 || idx >= sa->nr_entries || sa->entries[idx] == NULL) {
578 size_t printed = scnprintf(bf, size, intfmt, val);
579 if (show_prefix)
580 printed += scnprintf(bf + printed, size - printed, " /* %s??? */", sa->prefix);
581 return printed;
582 }
583
584 return scnprintf(bf, size, "%s%s", show_prefix ? sa->prefix : "", sa->entries[idx]);
585}
586
587static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
588 const char *intfmt,
589 struct syscall_arg *arg)
590{
591 return strarray__scnprintf(arg->parm, bf, size, intfmt, arg->show_string_prefix, arg->val);
592}
593
594static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
595 struct syscall_arg *arg)
596{
597 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
598}
599
600#define SCA_STRARRAY syscall_arg__scnprintf_strarray
601
602bool syscall_arg__strtoul_strarray(char *bf, size_t size, struct syscall_arg *arg, u64 *ret)
603{
604 return strarray__strtoul(arg->parm, bf, size, ret);
605}
606
607bool syscall_arg__strtoul_strarray_flags(char *bf, size_t size, struct syscall_arg *arg, u64 *ret)
608{
609 return strarray__strtoul_flags(arg->parm, bf, size, ret);
610}
611
612bool syscall_arg__strtoul_strarrays(char *bf, size_t size, struct syscall_arg *arg, u64 *ret)
613{
614 return strarrays__strtoul(arg->parm, bf, size, ret);
615}
616
617size_t syscall_arg__scnprintf_strarray_flags(char *bf, size_t size, struct syscall_arg *arg)
618{
619 return strarray__scnprintf_flags(arg->parm, bf, size, arg->show_string_prefix, arg->val);
620}
621
622size_t strarrays__scnprintf(struct strarrays *sas, char *bf, size_t size, const char *intfmt, bool show_prefix, int val)
623{
624 size_t printed;
625 int i;
626
627 for (i = 0; i < sas->nr_entries; ++i) {
628 struct strarray *sa = sas->entries[i];
629 int idx = val - sa->offset;
630
631 if (idx >= 0 && idx < sa->nr_entries) {
632 if (sa->entries[idx] == NULL)
633 break;
634 return scnprintf(bf, size, "%s%s", show_prefix ? sa->prefix : "", sa->entries[idx]);
635 }
636 }
637
638 printed = scnprintf(bf, size, intfmt, val);
639 if (show_prefix)
640 printed += scnprintf(bf + printed, size - printed, " /* %s??? */", sas->entries[0]->prefix);
641 return printed;
642}
643
644bool strarray__strtoul(struct strarray *sa, char *bf, size_t size, u64 *ret)
645{
646 int i;
647
648 for (i = 0; i < sa->nr_entries; ++i) {
649 if (sa->entries[i] && strncmp(sa->entries[i], bf, size) == 0 && sa->entries[i][size] == '\0') {
650 *ret = sa->offset + i;
651 return true;
652 }
653 }
654
655 return false;
656}
657
658bool strarray__strtoul_flags(struct strarray *sa, char *bf, size_t size, u64 *ret)
659{
660 u64 val = 0;
661 char *tok = bf, *sep, *end;
662
663 *ret = 0;
664
665 while (size != 0) {
666 int toklen = size;
667
668 sep = memchr(tok, '|', size);
669 if (sep != NULL) {
670 size -= sep - tok + 1;
671
672 end = sep - 1;
673 while (end > tok && isspace(*end))
674 --end;
675
676 toklen = end - tok + 1;
677 }
678
679 while (isspace(*tok))
680 ++tok;
681
682 if (isalpha(*tok) || *tok == '_') {
683 if (!strarray__strtoul(sa, tok, toklen, &val))
684 return false;
685 } else
686 val = strtoul(tok, NULL, 0);
687
688 *ret |= (1 << (val - 1));
689
690 if (sep == NULL)
691 break;
692 tok = sep + 1;
693 }
694
695 return true;
696}
697
698bool strarrays__strtoul(struct strarrays *sas, char *bf, size_t size, u64 *ret)
699{
700 int i;
701
702 for (i = 0; i < sas->nr_entries; ++i) {
703 struct strarray *sa = sas->entries[i];
704
705 if (strarray__strtoul(sa, bf, size, ret))
706 return true;
707 }
708
709 return false;
710}
711
712size_t syscall_arg__scnprintf_strarrays(char *bf, size_t size,
713 struct syscall_arg *arg)
714{
715 return strarrays__scnprintf(arg->parm, bf, size, "%d", arg->show_string_prefix, arg->val);
716}
717
718#ifndef AT_FDCWD
719#define AT_FDCWD -100
720#endif
721
722static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
723 struct syscall_arg *arg)
724{
725 int fd = arg->val;
726 const char *prefix = "AT_FD";
727
728 if (fd == AT_FDCWD)
729 return scnprintf(bf, size, "%s%s", arg->show_string_prefix ? prefix : "", "CWD");
730
731 return syscall_arg__scnprintf_fd(bf, size, arg);
732}
733
734#define SCA_FDAT syscall_arg__scnprintf_fd_at
735
736static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
737 struct syscall_arg *arg);
738
739#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
740
741size_t syscall_arg__scnprintf_hex(char *bf, size_t size, struct syscall_arg *arg)
742{
743 return scnprintf(bf, size, "%#lx", arg->val);
744}
745
746size_t syscall_arg__scnprintf_ptr(char *bf, size_t size, struct syscall_arg *arg)
747{
748 if (arg->val == 0)
749 return scnprintf(bf, size, "NULL");
750 return syscall_arg__scnprintf_hex(bf, size, arg);
751}
752
753size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *arg)
754{
755 return scnprintf(bf, size, "%d", arg->val);
756}
757
758size_t syscall_arg__scnprintf_long(char *bf, size_t size, struct syscall_arg *arg)
759{
760 return scnprintf(bf, size, "%ld", arg->val);
761}
762
763static size_t syscall_arg__scnprintf_char_array(char *bf, size_t size, struct syscall_arg *arg)
764{
765 // XXX Hey, maybe for sched:sched_switch prev/next comm fields we can
766 // fill missing comms using thread__set_comm()...
767 // here or in a special syscall_arg__scnprintf_pid_sched_tp...
768 return scnprintf(bf, size, "\"%-.*s\"", arg->fmt->nr_entries ?: arg->len, arg->val);
769}
770
771#define SCA_CHAR_ARRAY syscall_arg__scnprintf_char_array
772
773static const char *bpf_cmd[] = {
774 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
775 "MAP_GET_NEXT_KEY", "PROG_LOAD", "OBJ_PIN", "OBJ_GET", "PROG_ATTACH",
776 "PROG_DETACH", "PROG_TEST_RUN", "PROG_GET_NEXT_ID", "MAP_GET_NEXT_ID",
777 "PROG_GET_FD_BY_ID", "MAP_GET_FD_BY_ID", "OBJ_GET_INFO_BY_FD",
778 "PROG_QUERY", "RAW_TRACEPOINT_OPEN", "BTF_LOAD", "BTF_GET_FD_BY_ID",
779 "TASK_FD_QUERY", "MAP_LOOKUP_AND_DELETE_ELEM", "MAP_FREEZE",
780 "BTF_GET_NEXT_ID", "MAP_LOOKUP_BATCH", "MAP_LOOKUP_AND_DELETE_BATCH",
781 "MAP_UPDATE_BATCH", "MAP_DELETE_BATCH", "LINK_CREATE", "LINK_UPDATE",
782 "LINK_GET_FD_BY_ID", "LINK_GET_NEXT_ID", "ENABLE_STATS", "ITER_CREATE",
783 "LINK_DETACH", "PROG_BIND_MAP",
784};
785static DEFINE_STRARRAY(bpf_cmd, "BPF_");
786
787static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
788static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, "EPOLL_CTL_", 1);
789
790static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
791static DEFINE_STRARRAY(itimers, "ITIMER_");
792
793static const char *keyctl_options[] = {
794 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
795 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
796 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
797 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
798 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
799};
800static DEFINE_STRARRAY(keyctl_options, "KEYCTL_");
801
802static const char *whences[] = { "SET", "CUR", "END",
803#ifdef SEEK_DATA
804"DATA",
805#endif
806#ifdef SEEK_HOLE
807"HOLE",
808#endif
809};
810static DEFINE_STRARRAY(whences, "SEEK_");
811
812static const char *fcntl_cmds[] = {
813 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
814 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "GETLK64",
815 "SETLK64", "SETLKW64", "SETOWN_EX", "GETOWN_EX",
816 "GETOWNER_UIDS",
817};
818static DEFINE_STRARRAY(fcntl_cmds, "F_");
819
820static const char *fcntl_linux_specific_cmds[] = {
821 "SETLEASE", "GETLEASE", "NOTIFY", "DUPFD_QUERY", [5] = "CANCELLK", "DUPFD_CLOEXEC",
822 "SETPIPE_SZ", "GETPIPE_SZ", "ADD_SEALS", "GET_SEALS",
823 "GET_RW_HINT", "SET_RW_HINT", "GET_FILE_RW_HINT", "SET_FILE_RW_HINT",
824};
825
826static DEFINE_STRARRAY_OFFSET(fcntl_linux_specific_cmds, "F_", F_LINUX_SPECIFIC_BASE);
827
828static struct strarray *fcntl_cmds_arrays[] = {
829 &strarray__fcntl_cmds,
830 &strarray__fcntl_linux_specific_cmds,
831};
832
833static DEFINE_STRARRAYS(fcntl_cmds_arrays);
834
835static const char *rlimit_resources[] = {
836 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
837 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
838 "RTTIME",
839};
840static DEFINE_STRARRAY(rlimit_resources, "RLIMIT_");
841
842static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
843static DEFINE_STRARRAY(sighow, "SIG_");
844
845static const char *clockid[] = {
846 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
847 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
848 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
849};
850static DEFINE_STRARRAY(clockid, "CLOCK_");
851
852static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
853 struct syscall_arg *arg)
854{
855 bool show_prefix = arg->show_string_prefix;
856 const char *suffix = "_OK";
857 size_t printed = 0;
858 int mode = arg->val;
859
860 if (mode == F_OK) /* 0 */
861 return scnprintf(bf, size, "F%s", show_prefix ? suffix : "");
862#define P_MODE(n) \
863 if (mode & n##_OK) { \
864 printed += scnprintf(bf + printed, size - printed, "%s%s", #n, show_prefix ? suffix : ""); \
865 mode &= ~n##_OK; \
866 }
867
868 P_MODE(R);
869 P_MODE(W);
870 P_MODE(X);
871#undef P_MODE
872
873 if (mode)
874 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
875
876 return printed;
877}
878
879#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
880
881static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
882 struct syscall_arg *arg);
883
884#define SCA_FILENAME syscall_arg__scnprintf_filename
885
886// 'argname' is just documentational at this point, to remove the previous comment with that info
887#define SCA_FILENAME_FROM_USER(argname) \
888 { .scnprintf = SCA_FILENAME, \
889 .from_user = true, }
890
891static size_t syscall_arg__scnprintf_buf(char *bf, size_t size, struct syscall_arg *arg);
892
893#define SCA_BUF syscall_arg__scnprintf_buf
894
895static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
896 struct syscall_arg *arg)
897{
898 bool show_prefix = arg->show_string_prefix;
899 const char *prefix = "O_";
900 int printed = 0, flags = arg->val;
901
902#define P_FLAG(n) \
903 if (flags & O_##n) { \
904 printed += scnprintf(bf + printed, size - printed, "%s%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \
905 flags &= ~O_##n; \
906 }
907
908 P_FLAG(CLOEXEC);
909 P_FLAG(NONBLOCK);
910#undef P_FLAG
911
912 if (flags)
913 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
914
915 return printed;
916}
917
918#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
919
920#ifndef GRND_NONBLOCK
921#define GRND_NONBLOCK 0x0001
922#endif
923#ifndef GRND_RANDOM
924#define GRND_RANDOM 0x0002
925#endif
926
927static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
928 struct syscall_arg *arg)
929{
930 bool show_prefix = arg->show_string_prefix;
931 const char *prefix = "GRND_";
932 int printed = 0, flags = arg->val;
933
934#define P_FLAG(n) \
935 if (flags & GRND_##n) { \
936 printed += scnprintf(bf + printed, size - printed, "%s%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \
937 flags &= ~GRND_##n; \
938 }
939
940 P_FLAG(RANDOM);
941 P_FLAG(NONBLOCK);
942#undef P_FLAG
943
944 if (flags)
945 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
946
947 return printed;
948}
949
950#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
951
952#ifdef HAVE_LIBBPF_SUPPORT
953static void syscall_arg_fmt__cache_btf_enum(struct syscall_arg_fmt *arg_fmt, struct btf *btf, char *type)
954{
955 int id;
956
957 type = strstr(type, "enum ");
958 if (type == NULL)
959 return;
960
961 type += 5; // skip "enum " to get the enumeration name
962
963 id = btf__find_by_name(btf, type);
964 if (id < 0)
965 return;
966
967 arg_fmt->type = btf__type_by_id(btf, id);
968}
969
970static bool syscall_arg__strtoul_btf_enum(char *bf, size_t size, struct syscall_arg *arg, u64 *val)
971{
972 const struct btf_type *bt = arg->fmt->type;
973 struct btf *btf = arg->trace->btf;
974 struct btf_enum *be = btf_enum(bt);
975
976 for (u32 i = 0; i < btf_vlen(bt); ++i, ++be) {
977 const char *name = btf__name_by_offset(btf, be->name_off);
978 int max_len = max(size, strlen(name));
979
980 if (strncmp(name, bf, max_len) == 0) {
981 *val = be->val;
982 return true;
983 }
984 }
985
986 return false;
987}
988
989static bool syscall_arg__strtoul_btf_type(char *bf, size_t size, struct syscall_arg *arg, u64 *val)
990{
991 const struct btf_type *bt;
992 char *type = arg->type_name;
993 struct btf *btf;
994
995 trace__load_vmlinux_btf(arg->trace);
996
997 btf = arg->trace->btf;
998 if (btf == NULL)
999 return false;
1000
1001 if (arg->fmt->type == NULL) {
1002 // See if this is an enum
1003 syscall_arg_fmt__cache_btf_enum(arg->fmt, btf, type);
1004 }
1005
1006 // Now let's see if we have a BTF type resolved
1007 bt = arg->fmt->type;
1008 if (bt == NULL)
1009 return false;
1010
1011 // If it is an enum:
1012 if (btf_is_enum(arg->fmt->type))
1013 return syscall_arg__strtoul_btf_enum(bf, size, arg, val);
1014
1015 return false;
1016}
1017
1018static size_t btf_enum_scnprintf(const struct btf_type *type, struct btf *btf, char *bf, size_t size, int val)
1019{
1020 struct btf_enum *be = btf_enum(type);
1021 const unsigned int nr_entries = btf_vlen(type);
1022
1023 for (unsigned int i = 0; i < nr_entries; ++i, ++be) {
1024 if (be->val == val) {
1025 return scnprintf(bf, size, "%s",
1026 btf__name_by_offset(btf, be->name_off));
1027 }
1028 }
1029
1030 return 0;
1031}
1032
1033struct trace_btf_dump_snprintf_ctx {
1034 char *bf;
1035 size_t printed, size;
1036};
1037
1038static void trace__btf_dump_snprintf(void *vctx, const char *fmt, va_list args)
1039{
1040 struct trace_btf_dump_snprintf_ctx *ctx = vctx;
1041
1042 ctx->printed += vscnprintf(ctx->bf + ctx->printed, ctx->size - ctx->printed, fmt, args);
1043}
1044
1045static size_t btf_struct_scnprintf(const struct btf_type *type, struct btf *btf, char *bf, size_t size, struct syscall_arg *arg)
1046{
1047 struct trace_btf_dump_snprintf_ctx ctx = {
1048 .bf = bf,
1049 .size = size,
1050 };
1051 struct augmented_arg *augmented_arg = arg->augmented.args;
1052 int type_id = arg->fmt->type_id, consumed;
1053 struct btf_dump *btf_dump;
1054
1055 LIBBPF_OPTS(btf_dump_opts, dump_opts);
1056 LIBBPF_OPTS(btf_dump_type_data_opts, dump_data_opts);
1057
1058 if (arg == NULL || arg->augmented.args == NULL)
1059 return 0;
1060
1061 dump_data_opts.compact = true;
1062 dump_data_opts.skip_names = !arg->trace->show_arg_names;
1063
1064 btf_dump = btf_dump__new(btf, trace__btf_dump_snprintf, &ctx, &dump_opts);
1065 if (btf_dump == NULL)
1066 return 0;
1067
1068 /* pretty print the struct data here */
1069 if (btf_dump__dump_type_data(btf_dump, type_id, arg->augmented.args->value, type->size, &dump_data_opts) == 0)
1070 return 0;
1071
1072 consumed = sizeof(*augmented_arg) + augmented_arg->size;
1073 arg->augmented.args = ((void *)arg->augmented.args) + consumed;
1074 arg->augmented.size -= consumed;
1075
1076 btf_dump__free(btf_dump);
1077
1078 return ctx.printed;
1079}
1080
1081static size_t trace__btf_scnprintf(struct trace *trace, struct syscall_arg *arg, char *bf,
1082 size_t size, int val, char *type)
1083{
1084 struct syscall_arg_fmt *arg_fmt = arg->fmt;
1085
1086 if (trace->btf == NULL)
1087 return 0;
1088
1089 if (arg_fmt->type == NULL) {
1090 // Check if this is an enum and if we have the BTF type for it.
1091 syscall_arg_fmt__cache_btf_enum(arg_fmt, trace->btf, type);
1092 }
1093
1094 // Did we manage to find a BTF type for the syscall/tracepoint argument?
1095 if (arg_fmt->type == NULL)
1096 return 0;
1097
1098 if (btf_is_enum(arg_fmt->type))
1099 return btf_enum_scnprintf(arg_fmt->type, trace->btf, bf, size, val);
1100 else if (btf_is_struct(arg_fmt->type) || btf_is_union(arg_fmt->type))
1101 return btf_struct_scnprintf(arg_fmt->type, trace->btf, bf, size, arg);
1102
1103 return 0;
1104}
1105
1106#else // HAVE_LIBBPF_SUPPORT
1107static size_t trace__btf_scnprintf(struct trace *trace __maybe_unused, struct syscall_arg *arg __maybe_unused,
1108 char *bf __maybe_unused, size_t size __maybe_unused, int val __maybe_unused,
1109 char *type __maybe_unused)
1110{
1111 return 0;
1112}
1113
1114static bool syscall_arg__strtoul_btf_type(char *bf __maybe_unused, size_t size __maybe_unused,
1115 struct syscall_arg *arg __maybe_unused, u64 *val __maybe_unused)
1116{
1117 return false;
1118}
1119#endif // HAVE_LIBBPF_SUPPORT
1120
1121#define STUL_BTF_TYPE syscall_arg__strtoul_btf_type
1122
1123#define STRARRAY(name, array) \
1124 { .scnprintf = SCA_STRARRAY, \
1125 .strtoul = STUL_STRARRAY, \
1126 .parm = &strarray__##array, \
1127 .show_zero = true, }
1128
1129#define STRARRAY_FLAGS(name, array) \
1130 { .scnprintf = SCA_STRARRAY_FLAGS, \
1131 .strtoul = STUL_STRARRAY_FLAGS, \
1132 .parm = &strarray__##array, \
1133 .show_zero = true, }
1134
1135static const struct syscall_fmt syscall_fmts[] = {
1136 { .name = "access",
1137 .arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, },
1138 { .name = "arch_prctl",
1139 .arg = { [0] = { .scnprintf = SCA_X86_ARCH_PRCTL_CODE, /* code */ },
1140 [1] = { .scnprintf = SCA_PTR, /* arg2 */ }, }, },
1141 { .name = "bind",
1142 .arg = { [0] = { .scnprintf = SCA_INT, /* fd */ },
1143 [1] = SCA_SOCKADDR_FROM_USER(umyaddr),
1144 [2] = { .scnprintf = SCA_INT, /* addrlen */ }, }, },
1145 { .name = "bpf",
1146 .arg = { [0] = STRARRAY(cmd, bpf_cmd),
1147 [1] = { .from_user = true /* attr */, }, } },
1148 { .name = "brk", .hexret = true,
1149 .arg = { [0] = { .scnprintf = SCA_PTR, /* brk */ }, }, },
1150 { .name = "clock_gettime",
1151 .arg = { [0] = STRARRAY(clk_id, clockid), }, },
1152 { .name = "clock_nanosleep",
1153 .arg = { [2] = SCA_TIMESPEC_FROM_USER(req), }, },
1154 { .name = "clone", .errpid = true, .nr_args = 5,
1155 .arg = { [0] = { .name = "flags", .scnprintf = SCA_CLONE_FLAGS, },
1156 [1] = { .name = "child_stack", .scnprintf = SCA_HEX, },
1157 [2] = { .name = "parent_tidptr", .scnprintf = SCA_HEX, },
1158 [3] = { .name = "child_tidptr", .scnprintf = SCA_HEX, },
1159 [4] = { .name = "tls", .scnprintf = SCA_HEX, }, }, },
1160 { .name = "close",
1161 .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, },
1162 { .name = "connect",
1163 .arg = { [0] = { .scnprintf = SCA_INT, /* fd */ },
1164 [1] = SCA_SOCKADDR_FROM_USER(servaddr),
1165 [2] = { .scnprintf = SCA_INT, /* addrlen */ }, }, },
1166 { .name = "epoll_ctl",
1167 .arg = { [1] = STRARRAY(op, epoll_ctl_ops), }, },
1168 { .name = "eventfd2",
1169 .arg = { [1] = { .scnprintf = SCA_EFD_FLAGS, /* flags */ }, }, },
1170 { .name = "faccessat",
1171 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ },
1172 [1] = SCA_FILENAME_FROM_USER(pathname),
1173 [2] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, },
1174 { .name = "faccessat2",
1175 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ },
1176 [1] = SCA_FILENAME_FROM_USER(pathname),
1177 [2] = { .scnprintf = SCA_ACCMODE, /* mode */ },
1178 [3] = { .scnprintf = SCA_FACCESSAT2_FLAGS, /* flags */ }, }, },
1179 { .name = "fchmodat",
1180 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
1181 { .name = "fchownat",
1182 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
1183 { .name = "fcntl",
1184 .arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */
1185 .strtoul = STUL_STRARRAYS,
1186 .parm = &strarrays__fcntl_cmds_arrays,
1187 .show_zero = true, },
1188 [2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, },
1189 { .name = "flock",
1190 .arg = { [1] = { .scnprintf = SCA_FLOCK, /* cmd */ }, }, },
1191 { .name = "fsconfig",
1192 .arg = { [1] = STRARRAY(cmd, fsconfig_cmds), }, },
1193 { .name = "fsmount",
1194 .arg = { [1] = { .scnprintf = SCA_FSMOUNT_FLAGS, /* fsmount_flags */
1195 .strtoul = STUL_STRARRAYS,
1196 .show_zero = true, },
1197 [2] = { .scnprintf = SCA_FSMOUNT_ATTR_FLAGS, /* attr_flags */ }, }, },
1198 { .name = "fspick",
1199 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
1200 [1] = SCA_FILENAME_FROM_USER(path),
1201 [2] = { .scnprintf = SCA_FSPICK_FLAGS, /* flags */ }, }, },
1202 { .name = "fstat", .alias = "newfstat", },
1203 { .name = "futex",
1204 .arg = { [1] = { .scnprintf = SCA_FUTEX_OP, /* op */ },
1205 [5] = { .scnprintf = SCA_FUTEX_VAL3, /* val3 */ }, }, },
1206 { .name = "futimesat",
1207 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
1208 { .name = "getitimer",
1209 .arg = { [0] = STRARRAY(which, itimers), }, },
1210 { .name = "getpid", .errpid = true, },
1211 { .name = "getpgid", .errpid = true, },
1212 { .name = "getppid", .errpid = true, },
1213 { .name = "getrandom",
1214 .arg = { [2] = { .scnprintf = SCA_GETRANDOM_FLAGS, /* flags */ }, }, },
1215 { .name = "getrlimit",
1216 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
1217 { .name = "getsockopt",
1218 .arg = { [1] = STRARRAY(level, socket_level), }, },
1219 { .name = "gettid", .errpid = true, },
1220 { .name = "ioctl",
1221 .arg = {
1222#if defined(__i386__) || defined(__x86_64__)
1223/*
1224 * FIXME: Make this available to all arches.
1225 */
1226 [1] = { .scnprintf = SCA_IOCTL_CMD, /* cmd */ },
1227 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
1228#else
1229 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
1230#endif
1231 { .name = "kcmp", .nr_args = 5,
1232 .arg = { [0] = { .name = "pid1", .scnprintf = SCA_PID, },
1233 [1] = { .name = "pid2", .scnprintf = SCA_PID, },
1234 [2] = { .name = "type", .scnprintf = SCA_KCMP_TYPE, },
1235 [3] = { .name = "idx1", .scnprintf = SCA_KCMP_IDX, },
1236 [4] = { .name = "idx2", .scnprintf = SCA_KCMP_IDX, }, }, },
1237 { .name = "keyctl",
1238 .arg = { [0] = STRARRAY(option, keyctl_options), }, },
1239 { .name = "kill",
1240 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
1241 { .name = "linkat",
1242 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
1243 { .name = "lseek",
1244 .arg = { [2] = STRARRAY(whence, whences), }, },
1245 { .name = "lstat", .alias = "newlstat", },
1246 { .name = "madvise",
1247 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
1248 [2] = { .scnprintf = SCA_MADV_BHV, /* behavior */ }, }, },
1249 { .name = "mkdirat",
1250 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
1251 { .name = "mknodat",
1252 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
1253 { .name = "mmap", .hexret = true,
1254/* The standard mmap maps to old_mmap on s390x */
1255#if defined(__s390x__)
1256 .alias = "old_mmap",
1257#endif
1258 .arg = { [2] = { .scnprintf = SCA_MMAP_PROT, .show_zero = true, /* prot */ },
1259 [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */
1260 .strtoul = STUL_STRARRAY_FLAGS,
1261 .parm = &strarray__mmap_flags, },
1262 [5] = { .scnprintf = SCA_HEX, /* offset */ }, }, },
1263 { .name = "mount",
1264 .arg = { [0] = SCA_FILENAME_FROM_USER(devname),
1265 [3] = { .scnprintf = SCA_MOUNT_FLAGS, /* flags */
1266 .mask_val = SCAMV_MOUNT_FLAGS, /* flags */ }, }, },
1267 { .name = "move_mount",
1268 .arg = { [0] = { .scnprintf = SCA_FDAT, /* from_dfd */ },
1269 [1] = SCA_FILENAME_FROM_USER(pathname),
1270 [2] = { .scnprintf = SCA_FDAT, /* to_dfd */ },
1271 [3] = SCA_FILENAME_FROM_USER(pathname),
1272 [4] = { .scnprintf = SCA_MOVE_MOUNT_FLAGS, /* flags */ }, }, },
1273 { .name = "mprotect",
1274 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
1275 [2] = { .scnprintf = SCA_MMAP_PROT, .show_zero = true, /* prot */ }, }, },
1276 { .name = "mq_unlink",
1277 .arg = { [0] = SCA_FILENAME_FROM_USER(u_name), }, },
1278 { .name = "mremap", .hexret = true,
1279 .arg = { [3] = { .scnprintf = SCA_MREMAP_FLAGS, /* flags */ }, }, },
1280 { .name = "name_to_handle_at",
1281 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
1282 { .name = "nanosleep",
1283 .arg = { [0] = SCA_TIMESPEC_FROM_USER(req), }, },
1284 { .name = "newfstatat", .alias = "fstatat",
1285 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ },
1286 [1] = SCA_FILENAME_FROM_USER(pathname),
1287 [3] = { .scnprintf = SCA_FS_AT_FLAGS, /* flags */ }, }, },
1288 { .name = "open",
1289 .arg = { [1] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
1290 { .name = "open_by_handle_at",
1291 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
1292 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
1293 { .name = "openat",
1294 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
1295 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
1296 { .name = "perf_event_open",
1297 .arg = { [0] = SCA_PERF_ATTR_FROM_USER(attr),
1298 [2] = { .scnprintf = SCA_INT, /* cpu */ },
1299 [3] = { .scnprintf = SCA_FD, /* group_fd */ },
1300 [4] = { .scnprintf = SCA_PERF_FLAGS, /* flags */ }, }, },
1301 { .name = "pipe2",
1302 .arg = { [1] = { .scnprintf = SCA_PIPE_FLAGS, /* flags */ }, }, },
1303 { .name = "pkey_alloc",
1304 .arg = { [1] = { .scnprintf = SCA_PKEY_ALLOC_ACCESS_RIGHTS, /* access_rights */ }, }, },
1305 { .name = "pkey_free",
1306 .arg = { [0] = { .scnprintf = SCA_INT, /* key */ }, }, },
1307 { .name = "pkey_mprotect",
1308 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
1309 [2] = { .scnprintf = SCA_MMAP_PROT, .show_zero = true, /* prot */ },
1310 [3] = { .scnprintf = SCA_INT, /* pkey */ }, }, },
1311 { .name = "poll", .timeout = true, },
1312 { .name = "ppoll", .timeout = true, },
1313 { .name = "prctl",
1314 .arg = { [0] = { .scnprintf = SCA_PRCTL_OPTION, /* option */
1315 .strtoul = STUL_STRARRAY,
1316 .parm = &strarray__prctl_options, },
1317 [1] = { .scnprintf = SCA_PRCTL_ARG2, /* arg2 */ },
1318 [2] = { .scnprintf = SCA_PRCTL_ARG3, /* arg3 */ }, }, },
1319 { .name = "pread", .alias = "pread64", },
1320 { .name = "preadv", .alias = "pread", },
1321 { .name = "prlimit64",
1322 .arg = { [1] = STRARRAY(resource, rlimit_resources),
1323 [2] = { .from_user = true /* new_rlim */, }, }, },
1324 { .name = "pwrite", .alias = "pwrite64", },
1325 { .name = "readlinkat",
1326 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
1327 { .name = "recvfrom",
1328 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
1329 { .name = "recvmmsg",
1330 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
1331 { .name = "recvmsg",
1332 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
1333 { .name = "renameat",
1334 .arg = { [0] = { .scnprintf = SCA_FDAT, /* olddirfd */ },
1335 [2] = { .scnprintf = SCA_FDAT, /* newdirfd */ }, }, },
1336 { .name = "renameat2",
1337 .arg = { [0] = { .scnprintf = SCA_FDAT, /* olddirfd */ },
1338 [2] = { .scnprintf = SCA_FDAT, /* newdirfd */ },
1339 [4] = { .scnprintf = SCA_RENAMEAT2_FLAGS, /* flags */ }, }, },
1340 { .name = "rseq",
1341 .arg = { [0] = { .from_user = true /* rseq */, }, }, },
1342 { .name = "rt_sigaction",
1343 .arg = { [0] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
1344 { .name = "rt_sigprocmask",
1345 .arg = { [0] = STRARRAY(how, sighow), }, },
1346 { .name = "rt_sigqueueinfo",
1347 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
1348 { .name = "rt_tgsigqueueinfo",
1349 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
1350 { .name = "sched_setscheduler",
1351 .arg = { [1] = { .scnprintf = SCA_SCHED_POLICY, /* policy */ }, }, },
1352 { .name = "seccomp",
1353 .arg = { [0] = { .scnprintf = SCA_SECCOMP_OP, /* op */ },
1354 [1] = { .scnprintf = SCA_SECCOMP_FLAGS, /* flags */ }, }, },
1355 { .name = "select", .timeout = true, },
1356 { .name = "sendfile", .alias = "sendfile64", },
1357 { .name = "sendmmsg",
1358 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
1359 { .name = "sendmsg",
1360 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
1361 { .name = "sendto",
1362 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ },
1363 [4] = SCA_SOCKADDR_FROM_USER(addr), }, },
1364 { .name = "set_robust_list",
1365 .arg = { [0] = { .from_user = true /* head */, }, }, },
1366 { .name = "set_tid_address", .errpid = true, },
1367 { .name = "setitimer",
1368 .arg = { [0] = STRARRAY(which, itimers), }, },
1369 { .name = "setrlimit",
1370 .arg = { [0] = STRARRAY(resource, rlimit_resources),
1371 [1] = { .from_user = true /* rlim */, }, }, },
1372 { .name = "setsockopt",
1373 .arg = { [1] = STRARRAY(level, socket_level), }, },
1374 { .name = "socket",
1375 .arg = { [0] = STRARRAY(family, socket_families),
1376 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ },
1377 [2] = { .scnprintf = SCA_SK_PROTO, /* protocol */ }, }, },
1378 { .name = "socketpair",
1379 .arg = { [0] = STRARRAY(family, socket_families),
1380 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ },
1381 [2] = { .scnprintf = SCA_SK_PROTO, /* protocol */ }, }, },
1382 { .name = "stat", .alias = "newstat", },
1383 { .name = "statx",
1384 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ },
1385 [2] = { .scnprintf = SCA_FS_AT_FLAGS, /* flags */ } ,
1386 [3] = { .scnprintf = SCA_STATX_MASK, /* mask */ }, }, },
1387 { .name = "swapoff",
1388 .arg = { [0] = SCA_FILENAME_FROM_USER(specialfile), }, },
1389 { .name = "swapon",
1390 .arg = { [0] = SCA_FILENAME_FROM_USER(specialfile), }, },
1391 { .name = "symlinkat",
1392 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
1393 { .name = "sync_file_range",
1394 .arg = { [3] = { .scnprintf = SCA_SYNC_FILE_RANGE_FLAGS, /* flags */ }, }, },
1395 { .name = "tgkill",
1396 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
1397 { .name = "tkill",
1398 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
1399 { .name = "umount2", .alias = "umount",
1400 .arg = { [0] = SCA_FILENAME_FROM_USER(name), }, },
1401 { .name = "uname", .alias = "newuname", },
1402 { .name = "unlinkat",
1403 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
1404 [1] = SCA_FILENAME_FROM_USER(pathname),
1405 [2] = { .scnprintf = SCA_FS_AT_FLAGS, /* flags */ }, }, },
1406 { .name = "utimensat",
1407 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, },
1408 { .name = "wait4", .errpid = true,
1409 .arg = { [2] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
1410 { .name = "waitid", .errpid = true,
1411 .arg = { [3] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
1412 { .name = "write",
1413 .arg = { [1] = { .scnprintf = SCA_BUF /* buf */, .from_user = true, }, }, },
1414};
1415
1416static int syscall_fmt__cmp(const void *name, const void *fmtp)
1417{
1418 const struct syscall_fmt *fmt = fmtp;
1419 return strcmp(name, fmt->name);
1420}
1421
1422static const struct syscall_fmt *__syscall_fmt__find(const struct syscall_fmt *fmts,
1423 const int nmemb,
1424 const char *name)
1425{
1426 return bsearch(name, fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1427}
1428
1429static const struct syscall_fmt *syscall_fmt__find(const char *name)
1430{
1431 const int nmemb = ARRAY_SIZE(syscall_fmts);
1432 return __syscall_fmt__find(syscall_fmts, nmemb, name);
1433}
1434
1435static const struct syscall_fmt *__syscall_fmt__find_by_alias(const struct syscall_fmt *fmts,
1436 const int nmemb, const char *alias)
1437{
1438 int i;
1439
1440 for (i = 0; i < nmemb; ++i) {
1441 if (fmts[i].alias && strcmp(fmts[i].alias, alias) == 0)
1442 return &fmts[i];
1443 }
1444
1445 return NULL;
1446}
1447
1448static const struct syscall_fmt *syscall_fmt__find_by_alias(const char *alias)
1449{
1450 const int nmemb = ARRAY_SIZE(syscall_fmts);
1451 return __syscall_fmt__find_by_alias(syscall_fmts, nmemb, alias);
1452}
1453
1454/**
1455 * struct syscall
1456 */
1457struct syscall {
1458 /** @e_machine: The ELF machine associated with the entry. */
1459 int e_machine;
1460 /** @id: id value from the tracepoint, the system call number. */
1461 int id;
1462 struct tep_event *tp_format;
1463 int nr_args;
1464 /**
1465 * @args_size: sum of the sizes of the syscall arguments, anything
1466 * after that is augmented stuff: pathname for openat, etc.
1467 */
1468
1469 int args_size;
1470 struct {
1471 struct bpf_program *sys_enter,
1472 *sys_exit;
1473 } bpf_prog;
1474 /** @is_exit: is this "exit" or "exit_group"? */
1475 bool is_exit;
1476 /**
1477 * @is_open: is this "open" or "openat"? To associate the fd returned in
1478 * sys_exit with the pathname in sys_enter.
1479 */
1480 bool is_open;
1481 /**
1482 * @nonexistent: Name lookup failed. Just a hole in the syscall table,
1483 * syscall id not allocated.
1484 */
1485 bool nonexistent;
1486 bool use_btf;
1487 struct tep_format_field *args;
1488 const char *name;
1489 const struct syscall_fmt *fmt;
1490 struct syscall_arg_fmt *arg_fmt;
1491};
1492
1493/*
1494 * We need to have this 'calculated' boolean because in some cases we really
1495 * don't know what is the duration of a syscall, for instance, when we start
1496 * a session and some threads are waiting for a syscall to finish, say 'poll',
1497 * in which case all we can do is to print "( ? ) for duration and for the
1498 * start timestamp.
1499 */
1500static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
1501{
1502 double duration = (double)t / NSEC_PER_MSEC;
1503 size_t printed = fprintf(fp, "(");
1504
1505 if (!calculated)
1506 printed += fprintf(fp, " ");
1507 else if (duration >= 1.0)
1508 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1509 else if (duration >= 0.01)
1510 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1511 else
1512 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
1513 return printed + fprintf(fp, "): ");
1514}
1515
1516/**
1517 * filename.ptr: The filename char pointer that will be vfs_getname'd
1518 * filename.entry_str_pos: Where to insert the string translated from
1519 * filename.ptr by the vfs_getname tracepoint/kprobe.
1520 * ret_scnprintf: syscall args may set this to a different syscall return
1521 * formatter, for instance, fcntl may return fds, file flags, etc.
1522 */
1523struct thread_trace {
1524 u64 entry_time;
1525 u32 entry_cpu;
1526 bool entry_pending;
1527 unsigned long nr_events;
1528 unsigned long pfmaj, pfmin;
1529 char *entry_str;
1530 double runtime_ms;
1531 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
1532 struct {
1533 unsigned long ptr;
1534 short int entry_str_pos;
1535 bool pending_open;
1536 unsigned int namelen;
1537 char *name;
1538 } filename;
1539 struct {
1540 int max;
1541 struct file *table;
1542 } files;
1543
1544 struct hashmap *syscall_stats;
1545};
1546
1547static size_t syscall_id_hash(long key, void *ctx __maybe_unused)
1548{
1549 return key;
1550}
1551
1552static bool syscall_id_equal(long key1, long key2, void *ctx __maybe_unused)
1553{
1554 return key1 == key2;
1555}
1556
1557static struct hashmap *alloc_syscall_stats(void)
1558{
1559 struct hashmap *result = hashmap__new(syscall_id_hash, syscall_id_equal, NULL);
1560
1561 return IS_ERR(result) ? NULL : result;
1562}
1563
1564static void delete_syscall_stats(struct hashmap *syscall_stats)
1565{
1566 struct hashmap_entry *pos;
1567 size_t bkt;
1568
1569 if (!syscall_stats)
1570 return;
1571
1572 hashmap__for_each_entry(syscall_stats, pos, bkt)
1573 zfree(&pos->pvalue);
1574 hashmap__free(syscall_stats);
1575}
1576
1577static struct thread_trace *thread_trace__new(struct trace *trace)
1578{
1579 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1580
1581 if (ttrace) {
1582 ttrace->files.max = -1;
1583 if (trace->summary) {
1584 ttrace->syscall_stats = alloc_syscall_stats();
1585 if (!ttrace->syscall_stats)
1586 zfree(&ttrace);
1587 }
1588 }
1589
1590 return ttrace;
1591}
1592
1593static void thread_trace__free_files(struct thread_trace *ttrace);
1594
1595static void thread_trace__delete(void *pttrace)
1596{
1597 struct thread_trace *ttrace = pttrace;
1598
1599 if (!ttrace)
1600 return;
1601
1602 delete_syscall_stats(ttrace->syscall_stats);
1603 ttrace->syscall_stats = NULL;
1604 thread_trace__free_files(ttrace);
1605 zfree(&ttrace->entry_str);
1606 free(ttrace);
1607}
1608
1609static struct thread_trace *thread__trace(struct thread *thread, struct trace *trace)
1610{
1611 struct thread_trace *ttrace;
1612
1613 if (thread == NULL)
1614 goto fail;
1615
1616 if (thread__priv(thread) == NULL)
1617 thread__set_priv(thread, thread_trace__new(trace));
1618
1619 if (thread__priv(thread) == NULL)
1620 goto fail;
1621
1622 ttrace = thread__priv(thread);
1623 ++ttrace->nr_events;
1624
1625 return ttrace;
1626fail:
1627 color_fprintf(trace->output, PERF_COLOR_RED,
1628 "WARNING: not enough memory, dropping samples!\n");
1629 return NULL;
1630}
1631
1632
1633void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
1634 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg))
1635{
1636 struct thread_trace *ttrace = thread__priv(arg->thread);
1637
1638 ttrace->ret_scnprintf = ret_scnprintf;
1639}
1640
1641#define TRACE_PFMAJ (1 << 0)
1642#define TRACE_PFMIN (1 << 1)
1643
1644static const size_t trace__entry_str_size = 2048;
1645
1646static void thread_trace__free_files(struct thread_trace *ttrace)
1647{
1648 for (int i = 0; i <= ttrace->files.max; ++i) {
1649 struct file *file = ttrace->files.table + i;
1650 zfree(&file->pathname);
1651 }
1652
1653 zfree(&ttrace->files.table);
1654 ttrace->files.max = -1;
1655}
1656
1657static struct file *thread_trace__files_entry(struct thread_trace *ttrace, int fd)
1658{
1659 if (fd < 0)
1660 return NULL;
1661
1662 if (fd > ttrace->files.max) {
1663 struct file *nfiles = realloc(ttrace->files.table, (fd + 1) * sizeof(struct file));
1664
1665 if (nfiles == NULL)
1666 return NULL;
1667
1668 if (ttrace->files.max != -1) {
1669 memset(nfiles + ttrace->files.max + 1, 0,
1670 (fd - ttrace->files.max) * sizeof(struct file));
1671 } else {
1672 memset(nfiles, 0, (fd + 1) * sizeof(struct file));
1673 }
1674
1675 ttrace->files.table = nfiles;
1676 ttrace->files.max = fd;
1677 }
1678
1679 return ttrace->files.table + fd;
1680}
1681
1682struct file *thread__files_entry(struct thread *thread, int fd)
1683{
1684 return thread_trace__files_entry(thread__priv(thread), fd);
1685}
1686
1687static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
1688{
1689 struct thread_trace *ttrace = thread__priv(thread);
1690 struct file *file = thread_trace__files_entry(ttrace, fd);
1691
1692 if (file != NULL) {
1693 struct stat st;
1694
1695 if (stat(pathname, &st) == 0)
1696 file->dev_maj = major(st.st_rdev);
1697 file->pathname = strdup(pathname);
1698 if (file->pathname)
1699 return 0;
1700 }
1701
1702 return -1;
1703}
1704
1705static int thread__read_fd_path(struct thread *thread, int fd)
1706{
1707 char linkname[PATH_MAX], pathname[PATH_MAX];
1708 struct stat st;
1709 int ret;
1710
1711 if (thread__pid(thread) == thread__tid(thread)) {
1712 scnprintf(linkname, sizeof(linkname),
1713 "/proc/%d/fd/%d", thread__pid(thread), fd);
1714 } else {
1715 scnprintf(linkname, sizeof(linkname),
1716 "/proc/%d/task/%d/fd/%d",
1717 thread__pid(thread), thread__tid(thread), fd);
1718 }
1719
1720 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1721 return -1;
1722
1723 ret = readlink(linkname, pathname, sizeof(pathname));
1724
1725 if (ret < 0 || ret > st.st_size)
1726 return -1;
1727
1728 pathname[ret] = '\0';
1729 return trace__set_fd_pathname(thread, fd, pathname);
1730}
1731
1732static const char *thread__fd_path(struct thread *thread, int fd,
1733 struct trace *trace)
1734{
1735 struct thread_trace *ttrace = thread__priv(thread);
1736
1737 if (ttrace == NULL || trace->fd_path_disabled)
1738 return NULL;
1739
1740 if (fd < 0)
1741 return NULL;
1742
1743 if ((fd > ttrace->files.max || ttrace->files.table[fd].pathname == NULL)) {
1744 if (!trace->live)
1745 return NULL;
1746 ++trace->stats.proc_getname;
1747 if (thread__read_fd_path(thread, fd))
1748 return NULL;
1749 }
1750
1751 return ttrace->files.table[fd].pathname;
1752}
1753
1754size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
1755{
1756 int fd = arg->val;
1757 size_t printed = scnprintf(bf, size, "%d", fd);
1758 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
1759
1760 if (path)
1761 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1762
1763 return printed;
1764}
1765
1766size_t pid__scnprintf_fd(struct trace *trace, pid_t pid, int fd, char *bf, size_t size)
1767{
1768 size_t printed = scnprintf(bf, size, "%d", fd);
1769 struct thread *thread = machine__find_thread(trace->host, pid, pid);
1770
1771 if (thread) {
1772 const char *path = thread__fd_path(thread, fd, trace);
1773
1774 if (path)
1775 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1776
1777 thread__put(thread);
1778 }
1779
1780 return printed;
1781}
1782
1783static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1784 struct syscall_arg *arg)
1785{
1786 int fd = arg->val;
1787 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1788 struct thread_trace *ttrace = thread__priv(arg->thread);
1789
1790 if (ttrace && fd >= 0 && fd <= ttrace->files.max)
1791 zfree(&ttrace->files.table[fd].pathname);
1792
1793 return printed;
1794}
1795
1796static void thread__set_filename_pos(struct thread *thread, const char *bf,
1797 unsigned long ptr)
1798{
1799 struct thread_trace *ttrace = thread__priv(thread);
1800
1801 ttrace->filename.ptr = ptr;
1802 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1803}
1804
1805static size_t syscall_arg__scnprintf_augmented_string(struct syscall_arg *arg, char *bf, size_t size)
1806{
1807 struct augmented_arg *augmented_arg = arg->augmented.args;
1808 size_t printed = scnprintf(bf, size, "\"%.*s\"", augmented_arg->size, augmented_arg->value);
1809 /*
1810 * So that the next arg with a payload can consume its augmented arg, i.e. for rename* syscalls
1811 * we would have two strings, each prefixed by its size.
1812 */
1813 int consumed = sizeof(*augmented_arg) + augmented_arg->size;
1814
1815 arg->augmented.args = ((void *)arg->augmented.args) + consumed;
1816 arg->augmented.size -= consumed;
1817
1818 return printed;
1819}
1820
1821static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1822 struct syscall_arg *arg)
1823{
1824 unsigned long ptr = arg->val;
1825
1826 if (arg->augmented.args)
1827 return syscall_arg__scnprintf_augmented_string(arg, bf, size);
1828
1829 if (!arg->trace->vfs_getname)
1830 return scnprintf(bf, size, "%#x", ptr);
1831
1832 thread__set_filename_pos(arg->thread, bf, ptr);
1833 return 0;
1834}
1835
1836#define MAX_CONTROL_CHAR 31
1837#define MAX_ASCII 127
1838
1839static size_t syscall_arg__scnprintf_buf(char *bf, size_t size, struct syscall_arg *arg)
1840{
1841 struct augmented_arg *augmented_arg = arg->augmented.args;
1842 unsigned char *orig = (unsigned char *)augmented_arg->value;
1843 size_t printed = 0;
1844 int consumed;
1845
1846 if (augmented_arg == NULL)
1847 return 0;
1848
1849 for (int j = 0; j < augmented_arg->size; ++j) {
1850 bool control_char = orig[j] <= MAX_CONTROL_CHAR || orig[j] >= MAX_ASCII;
1851 /* print control characters (0~31 and 127), and non-ascii characters in \(digits) */
1852 printed += scnprintf(bf + printed, size - printed, control_char ? "\\%d" : "%c", (int)orig[j]);
1853 }
1854
1855 consumed = sizeof(*augmented_arg) + augmented_arg->size;
1856 arg->augmented.args = ((void *)arg->augmented.args) + consumed;
1857 arg->augmented.size -= consumed;
1858
1859 return printed;
1860}
1861
1862static bool trace__filter_duration(struct trace *trace, double t)
1863{
1864 return t < (trace->duration_filter * NSEC_PER_MSEC);
1865}
1866
1867static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1868{
1869 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1870
1871 return fprintf(fp, "%10.3f ", ts);
1872}
1873
1874/*
1875 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1876 * using ttrace->entry_time for a thread that receives a sys_exit without
1877 * first having received a sys_enter ("poll" issued before tracing session
1878 * starts, lost sys_enter exit due to ring buffer overflow).
1879 */
1880static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1881{
1882 if (tstamp > 0)
1883 return __trace__fprintf_tstamp(trace, tstamp, fp);
1884
1885 return fprintf(fp, " ? ");
1886}
1887
1888/**
1889 * trace__fprintf_cpu - Print the CPU ID to a given file stream
1890 * @cpu: The CPU ID to print
1891 * @fp: The file stream to write to
1892 *
1893 * Formats and prints the specified CPU ID enclosed in brackets
1894 * (e.g., "[003] ") to the provided file pointer. It is used to
1895 * align and display the CPU ID consistently within the trace output.
1896 *
1897 * Return: The number of characters printed.
1898 */
1899static size_t trace__fprintf_cpu(u32 cpu, FILE *fp)
1900{
1901 size_t printed = 0;
1902
1903 if (cpu != (u32)-1)
1904 printed += fprintf(fp, "[%03u] ", cpu);
1905
1906 return printed;
1907}
1908
1909static pid_t workload_pid = -1;
1910static volatile sig_atomic_t done = false;
1911static volatile sig_atomic_t interrupted = false;
1912
1913static void sighandler_interrupt(int sig __maybe_unused)
1914{
1915 done = interrupted = true;
1916}
1917
1918static void sighandler_chld(int sig __maybe_unused, siginfo_t *info,
1919 void *context __maybe_unused)
1920{
1921 if (info->si_pid == workload_pid)
1922 done = true;
1923}
1924
1925static size_t trace__fprintf_comm_tid(struct trace *trace, struct thread *thread, FILE *fp)
1926{
1927 size_t printed = 0;
1928
1929 if (trace->multiple_threads) {
1930 if (trace->show_comm)
1931 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
1932 printed += fprintf(fp, "%d ", thread__tid(thread));
1933 }
1934
1935 return printed;
1936}
1937
1938static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
1939 u64 duration, bool duration_calculated,
1940 u64 tstamp, u32 cpu, FILE *fp)
1941{
1942 size_t printed = 0;
1943
1944 if (trace->show_tstamp)
1945 printed = trace__fprintf_tstamp(trace, tstamp, fp);
1946 if (trace->show_cpu && cpu != (u32)-1)
1947 printed += trace__fprintf_cpu(cpu, fp);
1948 if (trace->show_duration)
1949 printed += fprintf_duration(duration, duration_calculated, fp);
1950 return printed + trace__fprintf_comm_tid(trace, thread, fp);
1951}
1952
1953static int trace__process_event(struct trace *trace, struct machine *machine,
1954 union perf_event *event, struct perf_sample *sample)
1955{
1956 int ret = 0;
1957
1958 switch (event->header.type) {
1959 case PERF_RECORD_LOST:
1960 color_fprintf(trace->output, PERF_COLOR_RED,
1961 "LOST %" PRIu64 " events!\n", (u64)event->lost.lost);
1962 ret = machine__process_lost_event(machine, event, sample);
1963 break;
1964 default:
1965 ret = machine__process_event(machine, event, sample);
1966 break;
1967 }
1968
1969 return ret;
1970}
1971
1972static int trace__tool_process(const struct perf_tool *tool,
1973 union perf_event *event,
1974 struct perf_sample *sample,
1975 struct machine *machine)
1976{
1977 struct trace *trace = container_of(tool, struct trace, tool);
1978 return trace__process_event(trace, machine, event, sample);
1979}
1980
1981static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1982{
1983 struct machine *machine = vmachine;
1984
1985 if (machine->kptr_restrict_warned)
1986 return NULL;
1987
1988 if (symbol_conf.kptr_restrict) {
1989 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1990 "Check /proc/sys/kernel/kptr_restrict and /proc/sys/kernel/perf_event_paranoid.\n\n"
1991 "Kernel samples will not be resolved.\n");
1992 machine->kptr_restrict_warned = true;
1993 return NULL;
1994 }
1995
1996 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1997}
1998
1999static int trace__symbols_init(struct trace *trace, int argc, const char **argv,
2000 struct evlist *evlist)
2001{
2002 int err = symbol__init(NULL);
2003
2004 if (err)
2005 return err;
2006
2007 perf_env__init(&trace->host_env);
2008 err = perf_env__set_cmdline(&trace->host_env, argc, argv);
2009 if (err)
2010 goto out;
2011
2012 trace->host = machine__new_host(&trace->host_env);
2013 if (trace->host == NULL) {
2014 err = -ENOMEM;
2015 goto out;
2016 }
2017 thread__set_priv_destructor(thread_trace__delete);
2018
2019 err = trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr);
2020 if (err < 0)
2021 goto out;
2022
2023 if (trace->summary_only && trace->summary_mode != SUMMARY__BY_THREAD)
2024 goto out;
2025
2026 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
2027 evlist__core(evlist)->threads, trace__tool_process,
2028 /*needs_mmap=*/callchain_param.enabled &&
2029 !trace->summary_only,
2030 /*mmap_data=*/false,
2031 /*nr_threads_synthesize=*/1);
2032out:
2033 if (err) {
2034 perf_env__exit(&trace->host_env);
2035 symbol__exit();
2036 }
2037 return err;
2038}
2039
2040static void trace__symbols__exit(struct trace *trace)
2041{
2042 machine__exit(trace->host);
2043 trace->host = NULL;
2044
2045 perf_env__exit(&trace->host_env);
2046 symbol__exit();
2047}
2048
2049static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
2050{
2051 int idx;
2052
2053 if (nr_args == RAW_SYSCALL_ARGS_NUM && sc->fmt && sc->fmt->nr_args != 0)
2054 nr_args = sc->fmt->nr_args;
2055
2056 sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt));
2057 if (sc->arg_fmt == NULL)
2058 return -1;
2059
2060 for (idx = 0; idx < nr_args; ++idx) {
2061 if (sc->fmt)
2062 sc->arg_fmt[idx] = sc->fmt->arg[idx];
2063 }
2064
2065 sc->nr_args = nr_args;
2066 return 0;
2067}
2068
2069static const struct syscall_arg_fmt syscall_arg_fmts__by_name[] = {
2070 { .name = "msr", .scnprintf = SCA_X86_MSR, .strtoul = STUL_X86_MSR, },
2071 { .name = "vector", .scnprintf = SCA_X86_IRQ_VECTORS, .strtoul = STUL_X86_IRQ_VECTORS, },
2072};
2073
2074static int syscall_arg_fmt__cmp(const void *name, const void *fmtp)
2075{
2076 const struct syscall_arg_fmt *fmt = fmtp;
2077 return strcmp(name, fmt->name);
2078}
2079
2080static const struct syscall_arg_fmt *
2081__syscall_arg_fmt__find_by_name(const struct syscall_arg_fmt *fmts, const int nmemb,
2082 const char *name)
2083{
2084 return bsearch(name, fmts, nmemb, sizeof(struct syscall_arg_fmt), syscall_arg_fmt__cmp);
2085}
2086
2087static const struct syscall_arg_fmt *syscall_arg_fmt__find_by_name(const char *name)
2088{
2089 const int nmemb = ARRAY_SIZE(syscall_arg_fmts__by_name);
2090 return __syscall_arg_fmt__find_by_name(syscall_arg_fmts__by_name, nmemb, name);
2091}
2092
2093/*
2094 * v6.19 kernel added new fields to read userspace memory for event tracing.
2095 * But it's not used by perf and confuses the syscall parameters.
2096 */
2097static bool is_internal_field(struct tep_format_field *field)
2098{
2099 return !strcmp(field->type, "__data_loc char[]");
2100}
2101
2102static bool field_has_hex_fmt(struct tep_format_field *field, int len)
2103{
2104 const char *fmt, *pos, *end = NULL;
2105
2106 if (!field || !field->event || !field->event->print_fmt.format)
2107 return false;
2108
2109 fmt = field->event->print_fmt.format;
2110
2111 /* NB: Limit scanning strictly to the quoted printf format string */
2112 if (*fmt == '"') {
2113 const char *p = ++fmt;
2114
2115 while (*p) {
2116 if (*p == '\\' && p[1] != '\0') {
2117 /* NB: Skip escaped character */
2118 p += 2;
2119 } else if (*p == '"') {
2120 end = p;
2121 break;
2122 } else {
2123 p++;
2124 }
2125 }
2126 } else {
2127 end = strchr(fmt, ',');
2128 }
2129
2130 for (pos = strstr(fmt, field->name); pos && (!end || pos < end);
2131 pos = strstr(pos + 1, field->name)) {
2132 if (pos == fmt || !(isalnum(pos[-1]) || pos[-1] == '_')) {
2133 const char *after = pos + len;
2134
2135 if (*after == '=' && (strstarts(after + 1, "0x") ||
2136 strstarts(after + 1, "%#") ||
2137 strstarts(after + 1, "%p")))
2138 return true;
2139 }
2140 }
2141
2142 return false;
2143}
2144
2145static struct tep_format_field *
2146syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field *field,
2147 bool *use_btf)
2148{
2149 struct tep_format_field *last_field = NULL;
2150 int len;
2151
2152 for (; field; field = field->next, ++arg) {
2153 /* assume it's the last argument */
2154 if (is_internal_field(field))
2155 continue;
2156
2157 last_field = field;
2158
2159 if (arg->scnprintf)
2160 continue;
2161
2162 len = strlen(field->name);
2163
2164 // As far as heuristics (or intention) goes this seems to hold true, and makes sense!
2165 if ((field->flags & TEP_FIELD_IS_POINTER) && strstarts(field->type, "const "))
2166 arg->from_user = true;
2167
2168 if (strcmp(field->type, "const char *") == 0 &&
2169 ((len >= 4 && strcmp(field->name + len - 4, "name") == 0) ||
2170 strstr(field->name, "path") != NULL)) {
2171 arg->scnprintf = SCA_FILENAME;
2172 } else if ((field->flags & TEP_FIELD_IS_POINTER) || strstr(field->name, "addr") ||
2173 field_has_hex_fmt(field, len))
2174 arg->scnprintf = SCA_PTR;
2175 else if (strcmp(field->type, "pid_t") == 0)
2176 arg->scnprintf = SCA_PID;
2177 else if (strcmp(field->type, "umode_t") == 0)
2178 arg->scnprintf = SCA_MODE_T;
2179 else if ((field->flags & TEP_FIELD_IS_ARRAY) && strstr(field->type, "char")) {
2180 arg->scnprintf = SCA_CHAR_ARRAY;
2181 arg->nr_entries = field->arraylen;
2182 } else if ((strcmp(field->type, "int") == 0 ||
2183 strcmp(field->type, "unsigned int") == 0 ||
2184 strcmp(field->type, "long") == 0) &&
2185 len >= 2 && strcmp(field->name + len - 2, "fd") == 0) {
2186 /*
2187 * /sys/kernel/tracing/events/syscalls/sys_enter*
2188 * grep -E 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
2189 * 65 int
2190 * 23 unsigned int
2191 * 7 unsigned long
2192 */
2193 arg->scnprintf = SCA_FD;
2194 } else if (strstr(field->type, "enum") && use_btf != NULL) {
2195 *use_btf = true;
2196 arg->strtoul = STUL_BTF_TYPE;
2197 } else {
2198 const struct syscall_arg_fmt *fmt =
2199 syscall_arg_fmt__find_by_name(field->name);
2200
2201 if (fmt) {
2202 arg->scnprintf = fmt->scnprintf;
2203 arg->strtoul = fmt->strtoul;
2204 }
2205 }
2206 }
2207
2208 return last_field;
2209}
2210
2211static int syscall__set_arg_fmts(struct syscall *sc)
2212{
2213 struct tep_format_field *last_field = syscall_arg_fmt__init_array(sc->arg_fmt, sc->args,
2214 &sc->use_btf);
2215
2216 if (last_field)
2217 sc->args_size = last_field->offset + last_field->size;
2218
2219 return 0;
2220}
2221
2222static int syscall__read_info(struct syscall *sc, struct trace *trace)
2223{
2224 char tp_name[128];
2225 const char *name;
2226 struct tep_format_field *field;
2227 int err;
2228
2229 if (sc->nonexistent)
2230 return -EEXIST;
2231
2232 if (sc->name) {
2233 /* Info already read. */
2234 return 0;
2235 }
2236
2237 name = syscalltbl__name(sc->e_machine, sc->id);
2238 if (name == NULL) {
2239 sc->nonexistent = true;
2240 return -EEXIST;
2241 }
2242
2243 sc->name = name;
2244 sc->fmt = syscall_fmt__find(sc->name);
2245
2246 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
2247 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
2248
2249 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
2250 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
2251 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
2252 }
2253
2254 /*
2255 * Fails to read trace point format via sysfs node, so the trace point
2256 * doesn't exist. Set the 'nonexistent' flag as true.
2257 */
2258 if (IS_ERR(sc->tp_format)) {
2259 sc->nonexistent = true;
2260 err = PTR_ERR(sc->tp_format);
2261 sc->tp_format = NULL;
2262 return err;
2263 }
2264
2265 /*
2266 * The tracepoint format contains __syscall_nr field, so it's one more
2267 * than the actual number of syscall arguments.
2268 */
2269 if (syscall__alloc_arg_fmts(sc, sc->tp_format->format.nr_fields - 1))
2270 return -ENOMEM;
2271
2272 sc->args = sc->tp_format->format.fields;
2273 /*
2274 * We need to check and discard the first variable '__syscall_nr'
2275 * or 'nr' that mean the syscall number. It is needless here.
2276 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
2277 */
2278 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
2279 sc->args = sc->args->next;
2280 --sc->nr_args;
2281 }
2282
2283 field = sc->args;
2284 while (field) {
2285 if (is_internal_field(field))
2286 --sc->nr_args;
2287 field = field->next;
2288 }
2289
2290 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
2291 sc->is_open = !strcmp(name, "open") || !strcmp(name, "openat");
2292
2293 err = syscall__set_arg_fmts(sc);
2294
2295 /* after calling syscall__set_arg_fmts() we'll know whether use_btf is true */
2296 if (sc->use_btf)
2297 trace__load_vmlinux_btf(trace);
2298
2299 return err;
2300}
2301
2302static int evsel__init_tp_arg_scnprintf(struct evsel *evsel, bool *use_btf)
2303{
2304 struct syscall_arg_fmt *fmt = evsel__syscall_arg_fmt(evsel);
2305
2306 if (fmt != NULL) {
2307 const struct tep_event *tp_format = evsel__tp_format(evsel);
2308
2309 if (tp_format) {
2310 syscall_arg_fmt__init_array(fmt, tp_format->format.fields, use_btf);
2311 return 0;
2312 }
2313 }
2314
2315 return -ENOMEM;
2316}
2317
2318static int intcmp(const void *a, const void *b)
2319{
2320 const int *one = a, *another = b;
2321
2322 return *one - *another;
2323}
2324
2325static int trace__validate_ev_qualifier(struct trace *trace)
2326{
2327 int err = 0;
2328 bool printed_invalid_prefix = false;
2329 struct str_node *pos;
2330 size_t nr_used = 0, nr_allocated = strlist__nr_entries(trace->ev_qualifier);
2331
2332 trace->ev_qualifier_ids.entries = calloc(nr_allocated, sizeof(trace->ev_qualifier_ids.entries[0]));
2333 if (trace->ev_qualifier_ids.entries == NULL) {
2334 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
2335 trace->output);
2336 err = -EINVAL;
2337 goto out;
2338 }
2339
2340 strlist__for_each_entry(pos, trace->ev_qualifier) {
2341 const char *sc = pos->s;
2342 /*
2343 * TODO: Assume more than the validation/warnings are all for
2344 * the same binary type as perf.
2345 */
2346 int id = syscalltbl__id(EM_HOST, sc), match_next = -1;
2347
2348 if (id < 0) {
2349 id = syscalltbl__strglobmatch_first(EM_HOST, sc, &match_next);
2350 if (id >= 0)
2351 goto matches;
2352
2353 if (!printed_invalid_prefix) {
2354 pr_debug("Skipping unknown syscalls: ");
2355 printed_invalid_prefix = true;
2356 } else {
2357 pr_debug(", ");
2358 }
2359
2360 pr_debug("%s", sc);
2361 continue;
2362 }
2363matches:
2364 trace->ev_qualifier_ids.entries[nr_used++] = id;
2365 if (match_next == -1)
2366 continue;
2367
2368 while (1) {
2369 id = syscalltbl__strglobmatch_next(EM_HOST, sc, &match_next);
2370 if (id < 0)
2371 break;
2372 if (nr_allocated == nr_used) {
2373 void *entries;
2374
2375 nr_allocated += 8;
2376 entries = realloc(trace->ev_qualifier_ids.entries,
2377 nr_allocated * sizeof(trace->ev_qualifier_ids.entries[0]));
2378 if (entries == NULL) {
2379 err = -ENOMEM;
2380 fputs("\nError:\t Not enough memory for parsing\n", trace->output);
2381 goto out_free;
2382 }
2383 trace->ev_qualifier_ids.entries = entries;
2384 }
2385 trace->ev_qualifier_ids.entries[nr_used++] = id;
2386 }
2387 }
2388
2389 trace->ev_qualifier_ids.nr = nr_used;
2390 qsort(trace->ev_qualifier_ids.entries, nr_used, sizeof(int), intcmp);
2391out:
2392 if (printed_invalid_prefix)
2393 pr_debug("\n");
2394 return err;
2395out_free:
2396 zfree(&trace->ev_qualifier_ids.entries);
2397 trace->ev_qualifier_ids.nr = 0;
2398 goto out;
2399}
2400
2401static __maybe_unused bool trace__syscall_enabled(struct trace *trace, int id)
2402{
2403 bool in_ev_qualifier;
2404
2405 if (trace->ev_qualifier_ids.nr == 0)
2406 return true;
2407
2408 in_ev_qualifier = bsearch(&id, trace->ev_qualifier_ids.entries,
2409 trace->ev_qualifier_ids.nr, sizeof(int), intcmp) != NULL;
2410
2411 if (in_ev_qualifier)
2412 return !trace->not_ev_qualifier;
2413
2414 return trace->not_ev_qualifier;
2415}
2416
2417/*
2418 * args is to be interpreted as a series of longs but we need to handle
2419 * 8-byte unaligned accesses. args points to raw_data within the event
2420 * and raw_data is guaranteed to be 8-byte unaligned because it is
2421 * preceded by raw_size which is a u32. So we need to copy args to a temp
2422 * variable to read it. Most notably this avoids extended load instructions
2423 * on unaligned addresses
2424 */
2425unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
2426{
2427 unsigned long val;
2428 unsigned char *p = arg->args + sizeof(unsigned long) * idx;
2429
2430 memcpy(&val, p, sizeof(val));
2431 return val;
2432}
2433
2434static size_t syscall__scnprintf_name(struct syscall *sc, char *bf, size_t size,
2435 struct syscall_arg *arg)
2436{
2437 if (sc->arg_fmt && sc->arg_fmt[arg->idx].name)
2438 return scnprintf(bf, size, "%s: ", sc->arg_fmt[arg->idx].name);
2439
2440 return scnprintf(bf, size, "arg%d: ", arg->idx);
2441}
2442
2443/*
2444 * Check if the value is in fact zero, i.e. mask whatever needs masking, such
2445 * as mount 'flags' argument that needs ignoring some magic flag, see comment
2446 * in tools/perf/trace/beauty/mount_flags.c
2447 */
2448static unsigned long syscall_arg_fmt__mask_val(struct syscall_arg_fmt *fmt, struct syscall_arg *arg, unsigned long val)
2449{
2450 if (fmt && fmt->mask_val)
2451 return fmt->mask_val(arg, val);
2452
2453 return val;
2454}
2455
2456static size_t syscall_arg_fmt__scnprintf_val(struct syscall_arg_fmt *fmt, char *bf, size_t size,
2457 struct syscall_arg *arg, unsigned long val)
2458{
2459 if (fmt && fmt->scnprintf) {
2460 arg->val = val;
2461 if (fmt->parm)
2462 arg->parm = fmt->parm;
2463 return fmt->scnprintf(bf, size, arg);
2464 }
2465 return scnprintf(bf, size, "%ld", val);
2466}
2467
2468static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
2469 unsigned char *args, void *augmented_args, int augmented_args_size,
2470 struct trace *trace, struct thread *thread)
2471{
2472 size_t printed = 0, btf_printed;
2473 unsigned long val;
2474 u8 bit = 1;
2475 struct syscall_arg arg = {
2476 .args = args,
2477 .augmented = {
2478 .size = augmented_args_size,
2479 .args = augmented_args,
2480 },
2481 .idx = 0,
2482 .mask = 0,
2483 .trace = trace,
2484 .thread = thread,
2485 .show_string_prefix = trace->show_string_prefix,
2486 };
2487 struct thread_trace *ttrace = thread__priv(thread);
2488 void *default_scnprintf;
2489
2490 /*
2491 * Things like fcntl will set this in its 'cmd' formatter to pick the
2492 * right formatter for the return value (an fd? file flags?), which is
2493 * not needed for syscalls that always return a given type, say an fd.
2494 */
2495 ttrace->ret_scnprintf = NULL;
2496
2497 if (sc->args != NULL) {
2498 struct tep_format_field *field;
2499
2500 for (field = sc->args; field;
2501 field = field->next, ++arg.idx, bit <<= 1) {
2502 if (arg.mask & bit)
2503 continue;
2504
2505 arg.fmt = &sc->arg_fmt[arg.idx];
2506 val = syscall_arg__val(&arg, arg.idx);
2507 /*
2508 * Some syscall args need some mask, most don't and
2509 * return val untouched.
2510 */
2511 val = syscall_arg_fmt__mask_val(&sc->arg_fmt[arg.idx], &arg, val);
2512
2513 /*
2514 * Suppress this argument if its value is zero and show_zero
2515 * property isn't set.
2516 *
2517 * If it has a BTF type, then override the zero suppression knob
2518 * as the common case is for zero in an enum to have an associated entry.
2519 */
2520 if (val == 0 && !trace->show_zeros &&
2521 !(sc->arg_fmt && sc->arg_fmt[arg.idx].show_zero) &&
2522 !(sc->arg_fmt && sc->arg_fmt[arg.idx].strtoul == STUL_BTF_TYPE))
2523 continue;
2524
2525 printed += scnprintf(bf + printed, size - printed, "%s", printed ? ", " : "");
2526
2527 if (trace->show_arg_names)
2528 printed += scnprintf(bf + printed, size - printed, "%s: ", field->name);
2529
2530 default_scnprintf = sc->arg_fmt[arg.idx].scnprintf;
2531
2532 if (trace->force_btf || default_scnprintf == NULL || default_scnprintf == SCA_PTR) {
2533 btf_printed = trace__btf_scnprintf(trace, &arg, bf + printed,
2534 size - printed, val, field->type);
2535 if (btf_printed) {
2536 printed += btf_printed;
2537 continue;
2538 }
2539 }
2540
2541 printed += syscall_arg_fmt__scnprintf_val(&sc->arg_fmt[arg.idx],
2542 bf + printed, size - printed, &arg, val);
2543 }
2544 } else if (IS_ERR(sc->tp_format)) {
2545 /*
2546 * If we managed to read the tracepoint /format file, then we
2547 * may end up not having any args, like with gettid(), so only
2548 * print the raw args when we didn't manage to read it.
2549 */
2550 while (arg.idx < sc->nr_args) {
2551 if (arg.mask & bit)
2552 goto next_arg;
2553 val = syscall_arg__val(&arg, arg.idx);
2554 if (printed)
2555 printed += scnprintf(bf + printed, size - printed, ", ");
2556 printed += syscall__scnprintf_name(sc, bf + printed, size - printed, &arg);
2557 printed += syscall_arg_fmt__scnprintf_val(&sc->arg_fmt[arg.idx], bf + printed, size - printed, &arg, val);
2558next_arg:
2559 ++arg.idx;
2560 bit <<= 1;
2561 }
2562 }
2563
2564 return printed;
2565}
2566
2567static struct syscall *syscall__new(int e_machine, int id)
2568{
2569 struct syscall *sc = zalloc(sizeof(*sc));
2570
2571 if (!sc)
2572 return NULL;
2573
2574 sc->e_machine = e_machine;
2575 sc->id = id;
2576 return sc;
2577}
2578
2579static void syscall__delete(struct syscall *sc)
2580{
2581 if (!sc)
2582 return;
2583
2584 free(sc->arg_fmt);
2585 free(sc);
2586}
2587
2588static int syscall__bsearch_cmp(const void *key, const void *entry)
2589{
2590 const struct syscall *a = key, *b = *((const struct syscall **)entry);
2591
2592 if (a->e_machine != b->e_machine)
2593 return a->e_machine - b->e_machine;
2594
2595 return a->id - b->id;
2596}
2597
2598static int syscall__cmp(const void *va, const void *vb)
2599{
2600 const struct syscall *a = *((const struct syscall **)va);
2601 const struct syscall *b = *((const struct syscall **)vb);
2602
2603 if (a->e_machine != b->e_machine)
2604 return a->e_machine - b->e_machine;
2605
2606 return a->id - b->id;
2607}
2608
2609static struct syscall *trace__find_syscall(struct trace *trace, int e_machine, int id)
2610{
2611 struct syscall key = {
2612 .e_machine = e_machine,
2613 .id = id,
2614 };
2615 struct syscall *sc, **tmp;
2616
2617 if (trace->syscalls.table) {
2618 struct syscall **sc_entry = bsearch(&key, trace->syscalls.table,
2619 trace->syscalls.table_size,
2620 sizeof(trace->syscalls.table[0]),
2621 syscall__bsearch_cmp);
2622
2623 if (sc_entry)
2624 return *sc_entry;
2625 }
2626
2627 sc = syscall__new(e_machine, id);
2628 if (!sc)
2629 return NULL;
2630
2631 tmp = reallocarray(trace->syscalls.table, trace->syscalls.table_size + 1,
2632 sizeof(trace->syscalls.table[0]));
2633 if (!tmp) {
2634 syscall__delete(sc);
2635 return NULL;
2636 }
2637
2638 trace->syscalls.table = tmp;
2639 trace->syscalls.table[trace->syscalls.table_size++] = sc;
2640 qsort(trace->syscalls.table, trace->syscalls.table_size, sizeof(trace->syscalls.table[0]),
2641 syscall__cmp);
2642 return sc;
2643}
2644
2645typedef int (*tracepoint_handler)(struct trace *trace,
2646 union perf_event *event,
2647 struct perf_sample *sample);
2648
2649static struct syscall *trace__syscall_info(struct trace *trace, struct evsel *evsel,
2650 int e_machine, int id)
2651{
2652 struct syscall *sc;
2653 int err = 0;
2654
2655 if (id < 0) {
2656
2657 /*
2658 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
2659 * before that, leaving at a higher verbosity level till that is
2660 * explained. Reproduced with plain ftrace with:
2661 *
2662 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
2663 * grep "NR -1 " /t/trace_pipe
2664 *
2665 * After generating some load on the machine.
2666 */
2667 if (verbose > 1) {
2668 static u64 n;
2669 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
2670 id, evsel__name(evsel), ++n);
2671 }
2672 return NULL;
2673 }
2674
2675 err = -EINVAL;
2676
2677 sc = trace__find_syscall(trace, e_machine, id);
2678 if (sc)
2679 err = syscall__read_info(sc, trace);
2680
2681 if (err && verbose > 0) {
2682 errno = -err;
2683 fprintf(trace->output, "Problems reading syscall %d: %m", id);
2684 if (sc && sc->name)
2685 fprintf(trace->output, " (%s)", sc->name);
2686 fputs(" information\n", trace->output);
2687 }
2688 return err ? NULL : sc;
2689}
2690
2691struct syscall_stats {
2692 struct stats stats;
2693 u64 nr_failures;
2694 int max_errno;
2695 u32 *errnos;
2696};
2697
2698static void thread__update_stats(struct thread *thread, struct thread_trace *ttrace,
2699 int id, struct perf_sample *sample, long err,
2700 struct trace *trace)
2701{
2702 struct hashmap *syscall_stats = ttrace->syscall_stats;
2703 struct syscall_stats *stats = NULL;
2704 u64 duration = 0;
2705
2706 if (trace->summary_bpf)
2707 return;
2708
2709 if (trace->summary_mode == SUMMARY__BY_TOTAL)
2710 syscall_stats = trace->syscall_stats;
2711
2712 if (!hashmap__find(syscall_stats, id, &stats)) {
2713 stats = zalloc(sizeof(*stats));
2714 if (stats == NULL)
2715 return;
2716
2717 init_stats(&stats->stats);
2718 if (hashmap__add(syscall_stats, id, stats) < 0) {
2719 free(stats);
2720 return;
2721 }
2722 }
2723
2724 if (ttrace->entry_time && sample->time > ttrace->entry_time)
2725 duration = sample->time - ttrace->entry_time;
2726
2727 update_stats(&stats->stats, duration);
2728
2729 if (err < 0) {
2730 ++stats->nr_failures;
2731
2732 if (!trace->errno_summary)
2733 return;
2734
2735 err = -err;
2736 if (err > stats->max_errno) {
2737 u32 *new_errnos = realloc(stats->errnos, err * sizeof(u32));
2738
2739 if (new_errnos) {
2740 memset(new_errnos + stats->max_errno, 0, (err - stats->max_errno) * sizeof(u32));
2741 } else {
2742 pr_debug("Not enough memory for errno stats for thread \"%s\"(%d/%d), results will be incomplete\n",
2743 thread__comm_str(thread), thread__pid(thread),
2744 thread__tid(thread));
2745 return;
2746 }
2747
2748 stats->errnos = new_errnos;
2749 stats->max_errno = err;
2750 }
2751
2752 ++stats->errnos[err - 1];
2753 }
2754}
2755
2756static int trace__printf_interrupted_entry(struct trace *trace)
2757{
2758 struct thread_trace *ttrace;
2759 size_t printed;
2760 int len;
2761
2762 if (trace->failure_only || trace->current == NULL)
2763 return 0;
2764
2765 ttrace = thread__priv(trace->current);
2766
2767 if (!ttrace->entry_pending)
2768 return 0;
2769
2770 printed = trace__fprintf_entry_head(trace, trace->current, 0, false,
2771 ttrace->entry_time, ttrace->entry_cpu,
2772 trace->output);
2773 printed += len = fprintf(trace->output, "%s)", ttrace->entry_str);
2774
2775 if (len < trace->args_alignment - 4)
2776 printed += fprintf(trace->output, "%-*s", trace->args_alignment - 4 - len, " ");
2777
2778 printed += fprintf(trace->output, " ...\n");
2779
2780 ttrace->entry_pending = false;
2781 ++trace->nr_events_printed;
2782
2783 return printed;
2784}
2785
2786static int trace__fprintf_sample(struct trace *trace, struct perf_sample *sample,
2787 struct thread *thread)
2788{
2789 int printed = 0;
2790
2791 if (trace->print_sample) {
2792 double ts = (double)sample->time / NSEC_PER_MSEC;
2793
2794 printed += fprintf(trace->output, "%22s %10.3f %s %d/%d [%d]\n",
2795 evsel__name(sample->evsel), ts,
2796 thread__comm_str(thread),
2797 sample->pid, sample->tid, sample->cpu);
2798 }
2799
2800 return printed;
2801}
2802
2803static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sample, int *augmented_args_size, int raw_augmented_args_size)
2804{
2805 /*
2806 * For now with BPF raw_augmented we hook into raw_syscalls:sys_enter
2807 * and there we get all 6 syscall args plus the tracepoint common fields
2808 * that gets calculated at the start and the syscall_nr (another long).
2809 * So we check if that is the case and if so don't look after the
2810 * sc->args_size but always after the full raw_syscalls:sys_enter payload,
2811 * which is fixed.
2812 *
2813 * We'll revisit this later to pass s->args_size to the BPF augmenter
2814 * (now tools/perf/examples/bpf/augmented_raw_syscalls.c, so that it
2815 * copies only what we need for each syscall, like what happens when we
2816 * use syscalls:sys_enter_NAME, so that we reduce the kernel/userspace
2817 * traffic to just what is needed for each syscall.
2818 */
2819 int args_size = raw_augmented_args_size ?: sc->args_size;
2820
2821 *augmented_args_size = sample->raw_size - args_size;
2822 if (*augmented_args_size > 0) {
2823 static uintptr_t argbuf[1024]; /* assuming single-threaded */
2824
2825 if ((size_t)(*augmented_args_size) > sizeof(argbuf))
2826 return NULL;
2827
2828 /*
2829 * The perf ring-buffer is 8-byte aligned but sample->raw_data
2830 * is not because it's preceded by u32 size. Later, beautifier
2831 * will use the augmented args with stricter alignments like in
2832 * some struct. To make sure it's aligned, let's copy the args
2833 * into a static buffer as it's single-threaded for now.
2834 */
2835 memcpy(argbuf, sample->raw_data + args_size, *augmented_args_size);
2836
2837 return argbuf;
2838 }
2839 return NULL;
2840}
2841
2842static int trace__sys_enter(struct trace *trace,
2843 union perf_event *event __maybe_unused,
2844 struct perf_sample *sample)
2845{
2846 struct evsel *evsel = sample->evsel;
2847 char *msg;
2848 void *args;
2849 int printed = 0;
2850 struct thread *thread;
2851 int id = perf_evsel__sc_tp_uint(id, sample), err = -1;
2852 int augmented_args_size = 0, e_machine;
2853 void *augmented_args = NULL;
2854 struct syscall *sc;
2855 struct thread_trace *ttrace;
2856
2857 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2858 e_machine = thread__e_machine(thread, trace->host, /*e_flags=*/NULL);
2859 sc = trace__syscall_info(trace, evsel, e_machine, id);
2860 if (sc == NULL)
2861 goto out_put;
2862 ttrace = thread__trace(thread, trace);
2863 if (ttrace == NULL)
2864 goto out_put;
2865
2866 trace__fprintf_sample(trace, sample, thread);
2867
2868 args = perf_evsel__sc_tp_ptr(args, sample);
2869
2870 if (ttrace->entry_str == NULL) {
2871 ttrace->entry_str = malloc(trace__entry_str_size);
2872 if (!ttrace->entry_str)
2873 goto out_put;
2874 }
2875
2876 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
2877 trace__printf_interrupted_entry(trace);
2878 /*
2879 * If this is raw_syscalls.sys_enter, then it always comes with the 6 possible
2880 * arguments, even if the syscall being handled, say "openat", uses only 4 arguments
2881 * this breaks syscall__augmented_args() check for augmented args, as we calculate
2882 * syscall->args_size using each syscalls:sys_enter_NAME tracefs format file,
2883 * so when handling, say the openat syscall, we end up getting 6 args for the
2884 * raw_syscalls:sys_enter event, when we expected just 4, we end up mistakenly
2885 * thinking that the extra 2 u64 args are the augmented filename, so just check
2886 * here and avoid using augmented syscalls when the evsel is the raw_syscalls one.
2887 */
2888 if (evsel != trace->syscalls.events.sys_enter)
2889 augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls_args_size);
2890 ttrace->entry_time = sample->time;
2891 ttrace->entry_cpu = sample->cpu;
2892 msg = ttrace->entry_str;
2893 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
2894
2895 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
2896 args, augmented_args, augmented_args_size, trace, thread);
2897
2898 if (sc->is_exit) {
2899 if (!(trace->duration_filter || trace->summary_only || trace->failure_only || trace->min_stack)) {
2900 int alignment = 0;
2901
2902 trace__fprintf_entry_head(trace, thread, 0, false,
2903 ttrace->entry_time,
2904 sample->cpu, trace->output);
2905 printed = fprintf(trace->output, "%s)", ttrace->entry_str);
2906 if (trace->args_alignment > printed)
2907 alignment = trace->args_alignment - printed;
2908 fprintf(trace->output, "%*s= ?\n", alignment, " ");
2909 }
2910 } else {
2911 ttrace->entry_pending = true;
2912 /* See trace__vfs_getname & trace__sys_exit */
2913 ttrace->filename.pending_open = false;
2914 }
2915
2916 if (trace->current != thread) {
2917 thread__put(trace->current);
2918 trace->current = thread__get(thread);
2919 }
2920 err = 0;
2921out_put:
2922 thread__put(thread);
2923 return err;
2924}
2925
2926static int trace__fprintf_sys_enter(struct trace *trace, struct perf_sample *sample)
2927{
2928 struct thread_trace *ttrace;
2929 struct thread *thread;
2930 int id = perf_evsel__sc_tp_uint(id, sample), err = -1;
2931 struct syscall *sc;
2932 char msg[1024];
2933 void *args, *augmented_args = NULL;
2934 int augmented_args_size, e_machine;
2935 size_t printed = 0;
2936
2937
2938 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2939 e_machine = thread__e_machine(thread, trace->host, /*e_flags=*/NULL);
2940 sc = trace__syscall_info(trace, sample->evsel, e_machine, id);
2941 if (sc == NULL)
2942 goto out_put;
2943 ttrace = thread__trace(thread, trace);
2944 /*
2945 * We need to get ttrace just to make sure it is there when syscall__scnprintf_args()
2946 * and the rest of the beautifiers accessing it via struct syscall_arg touches it.
2947 */
2948 if (ttrace == NULL)
2949 goto out_put;
2950
2951 args = perf_evsel__sc_tp_ptr(args, sample);
2952 augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls_args_size);
2953 printed += syscall__scnprintf_args(sc, msg, sizeof(msg), args, augmented_args, augmented_args_size, trace, thread);
2954 fprintf(trace->output, "%.*s", (int)printed, msg);
2955 err = 0;
2956out_put:
2957 thread__put(thread);
2958 return err;
2959}
2960
2961static int trace__resolve_callchain(struct trace *trace,
2962 struct perf_sample *sample,
2963 struct callchain_cursor *cursor)
2964{
2965 struct evsel *evsel = sample->evsel;
2966 struct addr_location al;
2967 int max_stack = evsel->core.attr.sample_max_stack ?
2968 evsel->core.attr.sample_max_stack :
2969 trace->max_stack;
2970 int err = -1;
2971
2972 addr_location__init(&al);
2973 if (machine__resolve(trace->host, &al, sample) < 0)
2974 goto out;
2975
2976 err = thread__resolve_callchain(al.thread, cursor, sample, NULL, NULL, max_stack);
2977out:
2978 addr_location__exit(&al);
2979 return err;
2980}
2981
2982static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
2983{
2984 /* TODO: user-configurable print_opts */
2985 const unsigned int print_opts = EVSEL__PRINT_SYM |
2986 EVSEL__PRINT_DSO |
2987 EVSEL__PRINT_UNKNOWN_AS_ADDR;
2988
2989 return sample__fprintf_callchain(sample, 38, print_opts, get_tls_callchain_cursor(), symbol_conf.bt_stop_list, trace->output);
2990}
2991
2992static int trace__sys_exit(struct trace *trace,
2993 union perf_event *event __maybe_unused,
2994 struct perf_sample *sample)
2995{
2996 struct evsel *evsel = sample->evsel;
2997 long ret;
2998 u64 duration = 0;
2999 bool duration_calculated = false;
3000 struct thread *thread;
3001 int id = perf_evsel__sc_tp_uint(id, sample), err = -1, callchain_ret = 0, printed = 0;
3002 int alignment = trace->args_alignment, e_machine;
3003 struct syscall *sc;
3004 struct thread_trace *ttrace;
3005
3006 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
3007 e_machine = thread__e_machine(thread, trace->host, /*e_flags=*/NULL);
3008 sc = trace__syscall_info(trace, evsel, e_machine, id);
3009 if (sc == NULL)
3010 goto out_put;
3011 ttrace = thread__trace(thread, trace);
3012 if (ttrace == NULL)
3013 goto out_put;
3014
3015 trace__fprintf_sample(trace, sample, thread);
3016
3017 ret = perf_evsel__sc_tp_uint(ret, sample);
3018
3019 if (trace->summary)
3020 thread__update_stats(thread, ttrace, id, sample, ret, trace);
3021
3022 if (!trace->fd_path_disabled && sc->is_open && ret >= 0 && ttrace->filename.pending_open) {
3023 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
3024 ttrace->filename.pending_open = false;
3025 ++trace->stats.vfs_getname;
3026 }
3027
3028 if (ttrace->entry_time && sample->time >= ttrace->entry_time) {
3029 duration = sample->time - ttrace->entry_time;
3030 if (trace__filter_duration(trace, duration))
3031 goto out;
3032 duration_calculated = true;
3033 } else if (trace->duration_filter)
3034 goto out;
3035
3036 if (sample->callchain) {
3037 struct callchain_cursor *cursor = get_tls_callchain_cursor();
3038
3039 callchain_ret = trace__resolve_callchain(trace, sample, cursor);
3040 if (callchain_ret == 0) {
3041 if (cursor->nr < trace->min_stack)
3042 goto out;
3043 callchain_ret = 1;
3044 }
3045 }
3046
3047 if (trace->summary_only || (ret >= 0 && trace->failure_only))
3048 goto out;
3049
3050 trace__fprintf_entry_head(trace, thread, duration,
3051 duration_calculated, ttrace->entry_time,
3052 sample->cpu, trace->output);
3053
3054 if (ttrace->entry_pending) {
3055 printed = fprintf(trace->output, "%s", ttrace->entry_str);
3056 } else {
3057 printed += fprintf(trace->output, " ... [");
3058 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
3059 printed += 9;
3060 printed += fprintf(trace->output, "]: %s()", sc->name);
3061 }
3062
3063 printed++; /* the closing ')' */
3064
3065 if (alignment > printed)
3066 alignment -= printed;
3067 else
3068 alignment = 0;
3069
3070 fprintf(trace->output, ")%*s= ", alignment, " ");
3071
3072 if (sc->fmt == NULL) {
3073 if (ret < 0)
3074 goto errno_print;
3075signed_print:
3076 fprintf(trace->output, "%ld", ret);
3077 } else if (ret < 0) {
3078errno_print: {
3079 char bf[STRERR_BUFSIZE];
3080 const char *emsg = str_error_r(-ret, bf, sizeof(bf));
3081 const char *e = perf_env__arch_strerrno(e_machine, err);
3082
3083 fprintf(trace->output, "-1 %s (%s)", e, emsg);
3084 }
3085 } else if (ret == 0 && sc->fmt->timeout)
3086 fprintf(trace->output, "0 (Timeout)");
3087 else if (ttrace->ret_scnprintf) {
3088 char bf[1024];
3089 struct syscall_arg arg = {
3090 .val = ret,
3091 .thread = thread,
3092 .trace = trace,
3093 };
3094 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
3095 ttrace->ret_scnprintf = NULL;
3096 fprintf(trace->output, "%s", bf);
3097 } else if (sc->fmt->hexret)
3098 fprintf(trace->output, "%#lx", ret);
3099 else if (sc->fmt->errpid) {
3100 struct thread *child = machine__find_thread(trace->host, ret, ret);
3101
3102 fprintf(trace->output, "%ld", ret);
3103 if (child != NULL) {
3104 if (thread__comm_set(child))
3105 fprintf(trace->output, " (%s)", thread__comm_str(child));
3106 thread__put(child);
3107 }
3108 } else
3109 goto signed_print;
3110
3111 fputc('\n', trace->output);
3112
3113 /*
3114 * We only consider an 'event' for the sake of --max-events a non-filtered
3115 * sys_enter + sys_exit and other tracepoint events.
3116 */
3117 if (++trace->nr_events_printed == trace->max_events && trace->max_events != ULONG_MAX)
3118 interrupted = true;
3119
3120 if (callchain_ret > 0)
3121 trace__fprintf_callchain(trace, sample);
3122 else if (callchain_ret < 0)
3123 pr_err("Problem processing %s callchain, skipping...\n", evsel__name(evsel));
3124out:
3125 ttrace->entry_pending = false;
3126 err = 0;
3127out_put:
3128 thread__put(thread);
3129 return err;
3130}
3131
3132static int trace__vfs_getname(struct trace *trace,
3133 union perf_event *event __maybe_unused,
3134 struct perf_sample *sample)
3135{
3136 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
3137 struct thread_trace *ttrace;
3138 size_t filename_len, entry_str_len, to_move;
3139 ssize_t remaining_space;
3140 char *pos;
3141 const char *filename = perf_sample__strval(sample, "pathname");
3142
3143 if (!thread)
3144 goto out;
3145
3146 ttrace = thread__priv(thread);
3147 if (!ttrace)
3148 goto out_put;
3149
3150 filename_len = strlen(filename);
3151 if (filename_len == 0)
3152 goto out_put;
3153
3154 if (ttrace->filename.namelen < filename_len) {
3155 char *f = realloc(ttrace->filename.name, filename_len + 1);
3156
3157 if (f == NULL)
3158 goto out_put;
3159
3160 ttrace->filename.namelen = filename_len;
3161 ttrace->filename.name = f;
3162 }
3163
3164 strcpy(ttrace->filename.name, filename);
3165 ttrace->filename.pending_open = true;
3166
3167 if (!ttrace->filename.ptr)
3168 goto out_put;
3169
3170 entry_str_len = strlen(ttrace->entry_str);
3171 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
3172 if (remaining_space <= 0)
3173 goto out_put;
3174
3175 if (filename_len > (size_t)remaining_space) {
3176 filename += filename_len - remaining_space;
3177 filename_len = remaining_space;
3178 }
3179
3180 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
3181 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
3182 memmove(pos + filename_len, pos, to_move);
3183 memcpy(pos, filename, filename_len);
3184
3185 ttrace->filename.ptr = 0;
3186 ttrace->filename.entry_str_pos = 0;
3187out_put:
3188 thread__put(thread);
3189out:
3190 return 0;
3191}
3192
3193static int trace__sched_stat_runtime(struct trace *trace,
3194 union perf_event *event __maybe_unused,
3195 struct perf_sample *sample)
3196{
3197 u64 runtime = perf_sample__intval(sample, "runtime");
3198 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
3199 struct thread *thread = machine__findnew_thread(trace->host,
3200 sample->pid,
3201 sample->tid);
3202 struct thread_trace *ttrace = thread__trace(thread, trace);
3203
3204 if (ttrace == NULL)
3205 goto out_dump;
3206
3207 ttrace->runtime_ms += runtime_ms;
3208 trace->runtime_ms += runtime_ms;
3209out_put:
3210 thread__put(thread);
3211 return 0;
3212
3213out_dump:
3214 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
3215 sample->evsel->name,
3216 perf_sample__strval(sample, "comm"),
3217 (pid_t)perf_sample__intval(sample, "pid"),
3218 runtime,
3219 perf_sample__intval(sample, "vruntime"));
3220 goto out_put;
3221}
3222
3223static int bpf_output__printer(enum binary_printer_ops op,
3224 unsigned int val, void *extra __maybe_unused, FILE *fp)
3225{
3226 unsigned char ch = (unsigned char)val;
3227
3228 switch (op) {
3229 case BINARY_PRINT_CHAR_DATA:
3230 return fprintf(fp, "%c", isprint(ch) ? ch : '.');
3231 case BINARY_PRINT_DATA_BEGIN:
3232 case BINARY_PRINT_LINE_BEGIN:
3233 case BINARY_PRINT_ADDR:
3234 case BINARY_PRINT_NUM_DATA:
3235 case BINARY_PRINT_NUM_PAD:
3236 case BINARY_PRINT_SEP:
3237 case BINARY_PRINT_CHAR_PAD:
3238 case BINARY_PRINT_LINE_END:
3239 case BINARY_PRINT_DATA_END:
3240 default:
3241 break;
3242 }
3243
3244 return 0;
3245}
3246
3247static void bpf_output__fprintf(struct trace *trace,
3248 struct perf_sample *sample)
3249{
3250 binary__fprintf(sample->raw_data, sample->raw_size, 8,
3251 bpf_output__printer, NULL, trace->output);
3252 ++trace->nr_events_printed;
3253}
3254
3255static unsigned char bitmap_byte(const unsigned long *mask, int byte_idx)
3256{
3257 unsigned char b_val = 0;
3258 int bit_in_byte;
3259
3260 for (bit_in_byte = 0; bit_in_byte < 8; bit_in_byte++) {
3261 int b_idx = byte_idx * 8 + bit_in_byte;
3262 int host_w_idx = b_idx / BITS_PER_LONG;
3263 int host_bit_in_word = b_idx % BITS_PER_LONG;
3264
3265 if (mask[host_w_idx] & (1UL << host_bit_in_word))
3266 b_val |= (1 << bit_in_byte);
3267 }
3268 return b_val;
3269}
3270
3271static bool trace__field_is_ip(const char *name)
3272{
3273 return !strcmp(name, "__probe_ip") ||
3274 !strcmp(name, "caller_ip") ||
3275 !strcmp(name, "call_site");
3276}
3277
3278static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample *sample,
3279 struct thread *thread, void *augmented_args, int augmented_args_size)
3280{
3281 struct evsel *evsel = sample->evsel;
3282 char bf[2048];
3283 size_t size = sizeof(bf);
3284 const struct tep_event *tp_format = evsel__tp_format(evsel);
3285 struct tep_format_field *field = tp_format ? tp_format->format.fields : NULL;
3286 struct syscall_arg_fmt *arg = __evsel__syscall_arg_fmt(evsel);
3287 size_t printed = 0, btf_printed;
3288 unsigned long val;
3289 u8 bit = 1;
3290 bool is_probe_ip;
3291 struct syscall_arg syscall_arg = {
3292 .augmented = {
3293 .size = augmented_args_size,
3294 .args = augmented_args,
3295 },
3296 .idx = 0,
3297 .mask = 0,
3298 .trace = trace,
3299 .thread = thread,
3300 .show_string_prefix = trace->show_string_prefix,
3301 };
3302
3303 for (; field && arg; field = field->next, ++syscall_arg.idx, bit <<= 1, ++arg) {
3304 if (syscall_arg.mask & bit)
3305 continue;
3306
3307 syscall_arg.len = 0;
3308 syscall_arg.fmt = arg;
3309 if (field->flags & TEP_FIELD_IS_ARRAY) {
3310 void *ptr = format_field__get_raw_data(field, sample,
3311 evsel->needs_swap,
3312 &syscall_arg.len);
3313
3314 if (!ptr) {
3315 pr_err("Problem processing %s field, skipping...\n", field->name);
3316 continue;
3317 }
3318 val = (uintptr_t)ptr;
3319 } else if ((field->flags & TEP_FIELD_IS_DYNAMIC) &&
3320 strstr(field->type, "cpumask")) {
3321 unsigned long *mask = format_field__get_cpumask(field, sample,
3322 evsel->needs_swap,
3323 &syscall_arg.len);
3324
3325 if (!mask) {
3326 pr_err("Problem processing %s field, skipping...\n", field->name);
3327 continue;
3328 }
3329
3330 printed += scnprintf(bf + printed, size - printed, "%s", printed ? ", " : "");
3331 if (trace->show_arg_names)
3332 printed += scnprintf(bf + printed, size - printed, "%s: ", field->name);
3333
3334 if (syscall_arg.len == 0) {
3335 printed += scnprintf(bf + printed, size - printed, "0");
3336 } else if (trace->bitmask_list) {
3337 printed += bitmap_scnprintf(mask, syscall_arg.len * 8,
3338 bf + printed, size - printed);
3339 } else {
3340 int i;
3341 bool skip_zero = true;
3342
3343 printed += scnprintf(bf + printed, size - printed, "0x");
3344 /* Print bytes from most significant to least significant */
3345 for (i = syscall_arg.len - 1; i >= 0; i--) {
3346 unsigned char b_val = bitmap_byte(mask, i);
3347
3348 if (skip_zero && b_val == 0 && i > 0)
3349 continue;
3350
3351 if (skip_zero) {
3352 printed += scnprintf(bf + printed, size - printed, "%x", b_val);
3353 skip_zero = false;
3354 } else {
3355 printed += scnprintf(bf + printed, size - printed, "%02x", b_val);
3356 }
3357 }
3358 }
3359 free(mask);
3360 continue;
3361 } else
3362 val = format_field__intval(field, sample, evsel->needs_swap);
3363 /*
3364 * Some syscall args need some mask, most don't and
3365 * return val untouched.
3366 */
3367 val = syscall_arg_fmt__mask_val(arg, &syscall_arg, val);
3368
3369 /* Suppress this argument if its value is zero and show_zero property isn't set. */
3370 if (val == 0 && !trace->show_zeros && !arg->show_zero && arg->strtoul != STUL_BTF_TYPE)
3371 continue;
3372
3373 /*
3374 * __probe_ip is implicitly added to bare dynamic probes.
3375 * Suppress it by default to avoid cluttering the output.
3376 * If verbose mode is enabled, ensure it is formatted as a
3377 * hexadecimal memory address rather than a signed integer.
3378 *
3379 * caller_ip and call_site are also expected to be instruction
3380 * pointers and should always be represented in hexadecimal.
3381 */
3382 is_probe_ip = evsel__is_probe(evsel) && !strcmp(field->name, "__probe_ip");
3383
3384 if (is_probe_ip || trace__field_is_ip(field->name)) {
3385 if (is_probe_ip && !verbose)
3386 continue;
3387
3388 printed += scnprintf(bf + printed, size - printed,
3389 "%s", printed ? ", " : "");
3390 if (trace->show_arg_names)
3391 printed += scnprintf(bf + printed, size - printed,
3392 "%s: ", field->name);
3393
3394 printed += scnprintf(bf + printed, size - printed, "%#016llx",
3395 (unsigned long long)val);
3396 continue;
3397 }
3398
3399 printed += scnprintf(bf + printed, size - printed, "%s", printed ? ", " : "");
3400
3401 if (trace->show_arg_names)
3402 printed += scnprintf(bf + printed, size - printed, "%s: ", field->name);
3403
3404 btf_printed = trace__btf_scnprintf(trace, &syscall_arg, bf + printed, size - printed, val, field->type);
3405 if (btf_printed) {
3406 printed += btf_printed;
3407 continue;
3408 }
3409
3410 printed += syscall_arg_fmt__scnprintf_val(arg, bf + printed, size - printed, &syscall_arg, val);
3411 }
3412
3413 return fprintf(trace->output, "%.*s", (int)printed, bf);
3414}
3415
3416static int trace__event_handler(struct trace *trace,
3417 union perf_event *event __maybe_unused,
3418 struct perf_sample *sample)
3419{
3420 struct evsel *evsel = sample->evsel;
3421 struct thread *thread;
3422 int callchain_ret = 0;
3423
3424 if (evsel->nr_events_printed >= evsel->max_events)
3425 return 0;
3426
3427 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
3428
3429 if (sample->callchain) {
3430 struct callchain_cursor *cursor = get_tls_callchain_cursor();
3431
3432 callchain_ret = trace__resolve_callchain(trace, sample, cursor);
3433 if (callchain_ret == 0) {
3434 if (cursor->nr < trace->min_stack)
3435 goto out;
3436 callchain_ret = 1;
3437 }
3438 }
3439
3440 trace__printf_interrupted_entry(trace);
3441 trace__fprintf_tstamp(trace, sample->time, trace->output);
3442
3443 if (trace->show_cpu)
3444 trace__fprintf_cpu(sample->cpu, trace->output);
3445
3446 if (trace->trace_syscalls && trace->show_duration)
3447 fprintf(trace->output, "( ): ");
3448
3449 if (thread)
3450 trace__fprintf_comm_tid(trace, thread, trace->output);
3451
3452 if (evsel == trace->syscalls.events.bpf_output) {
3453 int id = perf_evsel__sc_tp_uint(id, sample);
3454 int e_machine = thread
3455 ? thread__e_machine(thread, trace->host, /*e_flags=*/NULL)
3456 : EM_HOST;
3457 struct syscall *sc = trace__syscall_info(trace, evsel, e_machine, id);
3458
3459 if (sc) {
3460 fprintf(trace->output, "%s(", sc->name);
3461 trace__fprintf_sys_enter(trace, sample);
3462 fputc(')', trace->output);
3463 goto newline;
3464 }
3465
3466 /*
3467 * XXX: Not having the associated syscall info or not finding/adding
3468 * the thread should never happen, but if it does...
3469 * fall thru and print it as a bpf_output event.
3470 */
3471 }
3472
3473 fprintf(trace->output, "%s(", evsel->name);
3474
3475 if (evsel__is_bpf_output(evsel)) {
3476 bpf_output__fprintf(trace, sample);
3477 } else {
3478 const struct tep_event *tp_format = evsel__tp_format(evsel);
3479
3480 if (tp_format && (strncmp(tp_format->name, "sys_enter_", 10) ||
3481 trace__fprintf_sys_enter(trace, sample))) {
3482 if (trace->libtraceevent_print) {
3483 event_format__fprintf(tp_format, sample->cpu,
3484 sample->raw_data, sample->raw_size,
3485 trace->output);
3486 } else {
3487 trace__fprintf_tp_fields(trace, sample, thread, NULL, 0);
3488 }
3489 }
3490 }
3491
3492newline:
3493 fprintf(trace->output, ")\n");
3494
3495 if (callchain_ret > 0)
3496 trace__fprintf_callchain(trace, sample);
3497 else if (callchain_ret < 0)
3498 pr_err("Problem processing %s callchain, skipping...\n", evsel__name(evsel));
3499
3500 ++trace->nr_events_printed;
3501
3502 if (evsel->max_events != ULONG_MAX && ++evsel->nr_events_printed == evsel->max_events) {
3503 evsel__disable(evsel);
3504 evsel__close(evsel);
3505 }
3506out:
3507 thread__put(thread);
3508 return 0;
3509}
3510
3511static void print_location(FILE *f, struct perf_sample *sample,
3512 struct addr_location *al,
3513 bool print_dso, bool print_sym)
3514{
3515
3516 if ((verbose > 0 || print_dso) && al->map)
3517 fprintf(f, "%s@", dso__long_name(map__dso(al->map)));
3518
3519 if ((verbose > 0 || print_sym) && al->sym)
3520 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
3521 al->addr - al->sym->start);
3522 else if (al->map)
3523 fprintf(f, "0x%" PRIx64, al->addr);
3524 else
3525 fprintf(f, "0x%" PRIx64, sample->addr);
3526}
3527
3528static int trace__pgfault(struct trace *trace,
3529 union perf_event *event __maybe_unused,
3530 struct perf_sample *sample)
3531{
3532 struct thread *thread;
3533 struct addr_location al;
3534 char map_type = 'd';
3535 struct thread_trace *ttrace;
3536 int err = -1;
3537 int callchain_ret = 0;
3538
3539 addr_location__init(&al);
3540 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
3541
3542 if (sample->callchain) {
3543 struct callchain_cursor *cursor = get_tls_callchain_cursor();
3544
3545 callchain_ret = trace__resolve_callchain(trace, sample, cursor);
3546 if (callchain_ret == 0) {
3547 if (cursor->nr < trace->min_stack)
3548 goto out_put;
3549 callchain_ret = 1;
3550 }
3551 }
3552
3553 ttrace = thread__trace(thread, trace);
3554 if (ttrace == NULL)
3555 goto out_put;
3556
3557 if (sample->evsel->core.attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ) {
3558 ttrace->pfmaj++;
3559 trace->pfmaj++;
3560 } else {
3561 ttrace->pfmin++;
3562 trace->pfmin++;
3563 }
3564
3565 if (trace->summary_only)
3566 goto out;
3567
3568 thread__find_symbol(thread, sample->cpumode, sample->ip, &al);
3569
3570 trace__fprintf_entry_head(trace, thread, 0, true, sample->time,
3571 sample->cpu, trace->output);
3572
3573 fprintf(trace->output, "%sfault [",
3574 sample->evsel->core.attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
3575 "maj" : "min");
3576
3577 print_location(trace->output, sample, &al, false, true);
3578
3579 fprintf(trace->output, "] => ");
3580
3581 thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
3582
3583 if (!al.map) {
3584 thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
3585
3586 if (al.map)
3587 map_type = 'x';
3588 else
3589 map_type = '?';
3590 }
3591
3592 print_location(trace->output, sample, &al, true, false);
3593
3594 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
3595
3596 if (callchain_ret > 0)
3597 trace__fprintf_callchain(trace, sample);
3598 else if (callchain_ret < 0)
3599 pr_err("Problem processing %s callchain, skipping...\n",
3600 evsel__name(sample->evsel));
3601
3602 ++trace->nr_events_printed;
3603out:
3604 err = 0;
3605out_put:
3606 thread__put(thread);
3607 addr_location__exit(&al);
3608 return err;
3609}
3610
3611static void trace__set_base_time(struct trace *trace,
3612 struct perf_sample *sample)
3613{
3614 /*
3615 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
3616 * and don't use sample->time unconditionally, we may end up having
3617 * some other event in the future without PERF_SAMPLE_TIME for good
3618 * reason, i.e. we may not be interested in its timestamps, just in
3619 * it taking place, picking some piece of information when it
3620 * appears in our event stream (vfs_getname comes to mind).
3621 */
3622 if (trace->base_time == 0 && !trace->full_time &&
3623 (sample->evsel->core.attr.sample_type & PERF_SAMPLE_TIME))
3624 trace->base_time = sample->time;
3625}
3626
3627static int trace__process_sample(const struct perf_tool *tool,
3628 union perf_event *event,
3629 struct perf_sample *sample,
3630 struct machine *machine __maybe_unused)
3631{
3632 struct trace *trace = container_of(tool, struct trace, tool);
3633 struct evsel *evsel = sample->evsel;
3634 struct thread *thread;
3635 int err = 0;
3636
3637 tracepoint_handler handler = evsel->handler;
3638
3639 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
3640 if (thread && thread__is_filtered(thread))
3641 goto out;
3642
3643 trace__set_base_time(trace, sample);
3644
3645 if (handler) {
3646 ++trace->nr_events;
3647 handler(trace, event, sample);
3648 }
3649out:
3650 thread__put(thread);
3651 return err;
3652}
3653
3654static int trace__record(struct trace *trace, int argc, const char **argv)
3655{
3656 unsigned int rec_argc, i, j;
3657 const char **rec_argv;
3658 const char * const record_args[] = {
3659 "record",
3660 "-R",
3661 "-m", "1024",
3662 "-c", "1",
3663 };
3664 pid_t pid = getpid();
3665 char *filter = asprintf__tp_filter_pids(1, &pid);
3666 const char * const sc_args[] = { "-e", };
3667 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
3668 const char * const majpf_args[] = { "-e", "major-faults" };
3669 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
3670 const char * const minpf_args[] = { "-e", "minor-faults" };
3671 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
3672 int err = -1;
3673
3674 /* +3 is for the event string below and the pid filter */
3675 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 3 +
3676 majpf_args_nr + minpf_args_nr + argc;
3677 rec_argv = calloc(rec_argc + 1, sizeof(char *));
3678
3679 if (rec_argv == NULL || filter == NULL)
3680 goto out_free;
3681
3682 j = 0;
3683 for (i = 0; i < ARRAY_SIZE(record_args); i++)
3684 rec_argv[j++] = record_args[i];
3685
3686 if (trace->trace_syscalls) {
3687 for (i = 0; i < sc_args_nr; i++)
3688 rec_argv[j++] = sc_args[i];
3689
3690 /* event string may be different for older kernels - e.g., RHEL6 */
3691 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
3692 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
3693 else if (is_valid_tracepoint("syscalls:sys_enter"))
3694 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
3695 else {
3696 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
3697 goto out_free;
3698 }
3699 }
3700
3701 rec_argv[j++] = "--filter";
3702 rec_argv[j++] = filter;
3703
3704 if (trace->trace_pgfaults & TRACE_PFMAJ)
3705 for (i = 0; i < majpf_args_nr; i++)
3706 rec_argv[j++] = majpf_args[i];
3707
3708 if (trace->trace_pgfaults & TRACE_PFMIN)
3709 for (i = 0; i < minpf_args_nr; i++)
3710 rec_argv[j++] = minpf_args[i];
3711
3712 for (i = 0; i < (unsigned int)argc; i++)
3713 rec_argv[j++] = argv[i];
3714
3715 err = cmd_record(j, rec_argv);
3716out_free:
3717 free(filter);
3718 free(rec_argv);
3719 return err;
3720}
3721
3722static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
3723static size_t trace__fprintf_total_summary(struct trace *trace, FILE *fp);
3724
3725static bool evlist__add_vfs_getname(struct evlist *evlist)
3726{
3727 bool found = false;
3728 struct evsel *evsel, *tmp;
3729 struct parse_events_error err;
3730 int ret;
3731
3732 parse_events_error__init(&err);
3733 ret = parse_events(evlist, "probe:vfs_getname*", &err);
3734 parse_events_error__exit(&err);
3735 if (ret)
3736 return false;
3737
3738 evlist__for_each_entry_safe(evlist, evsel, tmp) {
3739 if (!strstarts(evsel__name(evsel), "probe:vfs_getname"))
3740 continue;
3741
3742 if (evsel__field(evsel, "pathname")) {
3743 evsel->handler = trace__vfs_getname;
3744 found = true;
3745 continue;
3746 }
3747
3748 list_del_init(&evsel->core.node);
3749 evsel->evlist = NULL;
3750 evsel__put(evsel);
3751 }
3752
3753 return found;
3754}
3755
3756static struct evsel *evsel__new_pgfault(u64 config)
3757{
3758 struct evsel *evsel;
3759 struct perf_event_attr attr = {
3760 .type = PERF_TYPE_SOFTWARE,
3761 .mmap_data = 1,
3762 };
3763
3764 attr.config = config;
3765 attr.sample_period = 1;
3766
3767 event_attr_init(&attr);
3768
3769 evsel = evsel__new(&attr);
3770 if (evsel)
3771 evsel->handler = trace__pgfault;
3772
3773 return evsel;
3774}
3775
3776static void evlist__free_syscall_tp_fields(struct evlist *evlist)
3777{
3778 struct evsel *evsel;
3779
3780 evlist__for_each_entry(evlist, evsel) {
3781 evsel_trace__delete(evsel->priv);
3782 evsel->priv = NULL;
3783 }
3784}
3785
3786static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
3787{
3788 const u32 type = event->header.type;
3789
3790 if (type != PERF_RECORD_SAMPLE) {
3791 trace__process_event(trace, trace->host, event, sample);
3792 return;
3793 }
3794
3795 if (sample->evsel == NULL) {
3796 sample->evsel = evlist__id2evsel(trace->evlist, sample->id);
3797 if (sample->evsel)
3798 evsel__get(sample->evsel);
3799 }
3800
3801 if (sample->evsel == NULL) {
3802 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
3803 return;
3804 }
3805
3806 if (evswitch__discard(&trace->evswitch, sample->evsel))
3807 return;
3808
3809 trace__set_base_time(trace, sample);
3810
3811 if (sample->evsel->core.attr.type == PERF_TYPE_TRACEPOINT &&
3812 sample->raw_data == NULL) {
3813 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
3814 evsel__name(sample->evsel), sample->tid,
3815 sample->cpu, sample->raw_size);
3816 } else {
3817 tracepoint_handler handler = sample->evsel->handler;
3818
3819 handler(trace, event, sample);
3820 }
3821
3822 if (trace->nr_events_printed >= trace->max_events && trace->max_events != ULONG_MAX)
3823 interrupted = true;
3824}
3825
3826static int trace__add_syscall_newtp(struct trace *trace)
3827{
3828 int ret = -1;
3829 struct evlist *evlist = trace->evlist;
3830 struct evsel *sys_enter, *sys_exit;
3831
3832 sys_enter = perf_evsel__raw_syscall_newtp("sys_enter", trace__sys_enter);
3833 if (sys_enter == NULL)
3834 goto out;
3835
3836 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
3837 goto out_delete_sys_enter;
3838
3839 sys_exit = perf_evsel__raw_syscall_newtp("sys_exit", trace__sys_exit);
3840 if (sys_exit == NULL)
3841 goto out_delete_sys_enter;
3842
3843 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
3844 goto out_delete_sys_exit;
3845
3846 evsel__config_callchain(sys_enter, &trace->opts, &callchain_param);
3847 evsel__config_callchain(sys_exit, &trace->opts, &callchain_param);
3848
3849 evlist__add(evlist, sys_enter);
3850 evlist__add(evlist, sys_exit);
3851
3852 if (callchain_param.enabled && !trace->kernel_syscallchains) {
3853 /*
3854 * We're interested only in the user space callchain
3855 * leading to the syscall, allow overriding that for
3856 * debugging reasons using --kernel_syscall_callchains
3857 */
3858 sys_exit->core.attr.exclude_callchain_kernel = 1;
3859 }
3860
3861 trace->syscalls.events.sys_enter = sys_enter;
3862 trace->syscalls.events.sys_exit = sys_exit;
3863
3864 ret = 0;
3865out:
3866 return ret;
3867
3868out_delete_sys_exit:
3869 evsel__put_and_free_priv(sys_exit);
3870out_delete_sys_enter:
3871 evsel__put_and_free_priv(sys_enter);
3872 goto out;
3873}
3874
3875static int trace__set_ev_qualifier_tp_filter(struct trace *trace)
3876{
3877 int err = -1;
3878 struct evsel *sys_exit;
3879 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
3880 trace->ev_qualifier_ids.nr,
3881 trace->ev_qualifier_ids.entries);
3882
3883 if (filter == NULL)
3884 goto out_enomem;
3885
3886 if (!evsel__append_tp_filter(trace->syscalls.events.sys_enter, filter)) {
3887 sys_exit = trace->syscalls.events.sys_exit;
3888 err = evsel__append_tp_filter(sys_exit, filter);
3889 }
3890
3891 free(filter);
3892out:
3893 return err;
3894out_enomem:
3895 errno = ENOMEM;
3896 goto out;
3897}
3898
3899#ifdef HAVE_LIBBPF_SUPPORT
3900
3901static struct bpf_program *unaugmented_prog;
3902
3903static int syscall_arg_fmt__cache_btf_struct(struct syscall_arg_fmt *arg_fmt, struct btf *btf, char *type)
3904{
3905 int id;
3906
3907 if (arg_fmt->type != NULL)
3908 return -1;
3909
3910 id = btf__find_by_name(btf, type);
3911 if (id < 0)
3912 return -1;
3913
3914 arg_fmt->type = btf__type_by_id(btf, id);
3915 arg_fmt->type_id = id;
3916
3917 return 0;
3918}
3919
3920static struct bpf_program *trace__find_syscall_bpf_prog(struct trace *trace __maybe_unused,
3921 struct syscall *sc,
3922 const char *prog_name, const char *type)
3923{
3924 struct bpf_program *prog;
3925
3926 if (prog_name == NULL) {
3927 char default_prog_name[256];
3928 scnprintf(default_prog_name, sizeof(default_prog_name), "tp/syscalls/sys_%s_%s", type, sc->name);
3929 prog = augmented_syscalls__find_by_title(default_prog_name);
3930 if (prog != NULL)
3931 goto out_found;
3932 if (sc->fmt && sc->fmt->alias) {
3933 scnprintf(default_prog_name, sizeof(default_prog_name), "tp/syscalls/sys_%s_%s", type, sc->fmt->alias);
3934 prog = augmented_syscalls__find_by_title(default_prog_name);
3935 if (prog != NULL)
3936 goto out_found;
3937 }
3938 goto out_unaugmented;
3939 }
3940
3941 prog = augmented_syscalls__find_by_title(prog_name);
3942
3943 if (prog != NULL) {
3944out_found:
3945 return prog;
3946 }
3947
3948 pr_debug("Couldn't find BPF prog \"%s\" to associate with syscalls:sys_%s_%s, not augmenting it\n",
3949 prog_name, type, sc->name);
3950out_unaugmented:
3951 return unaugmented_prog;
3952}
3953
3954static void trace__init_syscall_bpf_progs(struct trace *trace, int e_machine, int id)
3955{
3956 struct syscall *sc = trace__syscall_info(trace, NULL, e_machine, id);
3957
3958 if (sc == NULL)
3959 return;
3960
3961 sc->bpf_prog.sys_enter = trace__find_syscall_bpf_prog(trace, sc, sc->fmt ? sc->fmt->bpf_prog_name.sys_enter : NULL, "enter");
3962 sc->bpf_prog.sys_exit = trace__find_syscall_bpf_prog(trace, sc, sc->fmt ? sc->fmt->bpf_prog_name.sys_exit : NULL, "exit");
3963}
3964
3965static int trace__bpf_prog_sys_enter_fd(struct trace *trace, int e_machine, int id)
3966{
3967 struct syscall *sc = trace__syscall_info(trace, NULL, e_machine, id);
3968 return sc ? bpf_program__fd(sc->bpf_prog.sys_enter) : bpf_program__fd(unaugmented_prog);
3969}
3970
3971static int trace__bpf_prog_sys_exit_fd(struct trace *trace, int e_machine, int id)
3972{
3973 struct syscall *sc = trace__syscall_info(trace, NULL, e_machine, id);
3974 return sc ? bpf_program__fd(sc->bpf_prog.sys_exit) : bpf_program__fd(unaugmented_prog);
3975}
3976
3977static int trace__bpf_sys_enter_beauty_map(struct trace *trace, int e_machine, int key, unsigned int *beauty_array)
3978{
3979 struct tep_format_field *field;
3980 struct syscall *sc = trace__syscall_info(trace, NULL, e_machine, key);
3981 const struct btf_type *bt;
3982 char *struct_offset, *tmp, name[32];
3983 bool can_augment = false;
3984 int i, cnt;
3985
3986 if (sc == NULL)
3987 return -1;
3988
3989 trace__load_vmlinux_btf(trace);
3990 if (trace->btf == NULL)
3991 return -1;
3992
3993 for (i = 0, field = sc->args; field; ++i, field = field->next) {
3994 // XXX We're only collecting pointer payloads _from_ user space
3995 if (!sc->arg_fmt[i].from_user)
3996 continue;
3997
3998 struct_offset = strstr(field->type, "struct ");
3999 if (struct_offset == NULL)
4000 struct_offset = strstr(field->type, "union ");
4001 else
4002 struct_offset++; // "union" is shorter
4003
4004 if (field->flags & TEP_FIELD_IS_POINTER && struct_offset) { /* struct or union (think BPF's attr arg) */
4005 struct_offset += 6;
4006
4007 /* for 'struct foo *', we only want 'foo' */
4008 for (tmp = struct_offset, cnt = 0; *tmp != ' ' && *tmp != '\0'; ++tmp, ++cnt) {
4009 }
4010
4011 strncpy(name, struct_offset, cnt);
4012 name[cnt] = '\0';
4013
4014 /* cache struct's btf_type and type_id */
4015 if (syscall_arg_fmt__cache_btf_struct(&sc->arg_fmt[i], trace->btf, name))
4016 continue;
4017
4018 bt = sc->arg_fmt[i].type;
4019 beauty_array[i] = bt->size;
4020 can_augment = true;
4021 } else if (field->flags & TEP_FIELD_IS_POINTER && /* string */
4022 strcmp(field->type, "const char *") == 0 &&
4023 (strstr(field->name, "name") ||
4024 strstr(field->name, "path") ||
4025 strstr(field->name, "file") ||
4026 strstr(field->name, "root") ||
4027 strstr(field->name, "key") ||
4028 strstr(field->name, "special") ||
4029 strstr(field->name, "type") ||
4030 strstr(field->name, "description"))) {
4031 beauty_array[i] = 1;
4032 can_augment = true;
4033 } else if (field->flags & TEP_FIELD_IS_POINTER && /* buffer */
4034 strstr(field->type, "char *") &&
4035 (strstr(field->name, "buf") ||
4036 strstr(field->name, "val") ||
4037 strstr(field->name, "msg"))) {
4038 int j;
4039 struct tep_format_field *field_tmp;
4040
4041 /* find the size of the buffer that appears in pairs with buf */
4042 for (j = 0, field_tmp = sc->args; field_tmp; ++j, field_tmp = field_tmp->next) {
4043 if (!(field_tmp->flags & TEP_FIELD_IS_POINTER) && /* only integers */
4044 (strstr(field_tmp->name, "count") ||
4045 strstr(field_tmp->name, "siz") || /* size, bufsiz */
4046 (strstr(field_tmp->name, "len") && strcmp(field_tmp->name, "filename")))) {
4047 /* filename's got 'len' in it, we don't want that */
4048 beauty_array[i] = -(j + 1);
4049 can_augment = true;
4050 break;
4051 }
4052 }
4053 }
4054 }
4055
4056 if (can_augment)
4057 return 0;
4058
4059 return -1;
4060}
4061
4062static struct bpf_program *trace__find_usable_bpf_prog_entry(struct trace *trace,
4063 struct syscall *sc)
4064{
4065 struct tep_format_field *field, *candidate_field;
4066 /*
4067 * We're only interested in syscalls that have a pointer:
4068 */
4069 for (field = sc->args; field; field = field->next) {
4070 if (field->flags & TEP_FIELD_IS_POINTER)
4071 goto try_to_find_pair;
4072 }
4073
4074 return NULL;
4075
4076try_to_find_pair:
4077 for (int i = 0, num_idx = syscalltbl__num_idx(sc->e_machine); i < num_idx; ++i) {
4078 int id = syscalltbl__id_at_idx(sc->e_machine, i);
4079 struct syscall *pair = trace__syscall_info(trace, NULL, sc->e_machine, id);
4080 struct bpf_program *pair_prog;
4081 bool is_candidate = false;
4082
4083 if (pair == NULL || pair->id == sc->id ||
4084 pair->bpf_prog.sys_enter == unaugmented_prog)
4085 continue;
4086
4087 for (field = sc->args, candidate_field = pair->args;
4088 field && candidate_field; field = field->next, candidate_field = candidate_field->next) {
4089 bool is_pointer = field->flags & TEP_FIELD_IS_POINTER,
4090 candidate_is_pointer = candidate_field->flags & TEP_FIELD_IS_POINTER;
4091
4092 if (is_pointer) {
4093 if (!candidate_is_pointer) {
4094 // The candidate just doesn't copies our pointer arg, might copy other pointers we want.
4095 continue;
4096 }
4097 } else {
4098 if (candidate_is_pointer) {
4099 // The candidate might copy a pointer we don't have, skip it.
4100 goto next_candidate;
4101 }
4102 continue;
4103 }
4104
4105 if (strcmp(field->type, candidate_field->type))
4106 goto next_candidate;
4107
4108 /*
4109 * This is limited in the BPF program but sys_write
4110 * uses "const char *" for its "buf" arg so we need to
4111 * use some heuristic that is kinda future proof...
4112 */
4113 if (strcmp(field->type, "const char *") == 0 &&
4114 !(strstr(field->name, "name") ||
4115 strstr(field->name, "path") ||
4116 strstr(field->name, "file") ||
4117 strstr(field->name, "root") ||
4118 strstr(field->name, "description")))
4119 goto next_candidate;
4120
4121 is_candidate = true;
4122 }
4123
4124 if (!is_candidate)
4125 goto next_candidate;
4126
4127 /*
4128 * Check if the tentative pair syscall augmenter has more pointers, if it has,
4129 * then it may be collecting that and we then can't use it, as it would collect
4130 * more than what is common to the two syscalls.
4131 */
4132 if (candidate_field) {
4133 for (candidate_field = candidate_field->next; candidate_field; candidate_field = candidate_field->next)
4134 if (candidate_field->flags & TEP_FIELD_IS_POINTER)
4135 goto next_candidate;
4136 }
4137
4138 pair_prog = pair->bpf_prog.sys_enter;
4139 /*
4140 * If the pair isn't enabled, then its bpf_prog.sys_enter will not
4141 * have been searched for, so search it here and if it returns the
4142 * unaugmented one, then ignore it, otherwise we'll reuse that BPF
4143 * program for a filtered syscall on a non-filtered one.
4144 *
4145 * For instance, we have "!syscalls:sys_enter_renameat" and that is
4146 * useful for "renameat2".
4147 */
4148 if (pair_prog == NULL) {
4149 pair_prog = trace__find_syscall_bpf_prog(trace, pair, pair->fmt ? pair->fmt->bpf_prog_name.sys_enter : NULL, "enter");
4150 if (pair_prog == unaugmented_prog)
4151 goto next_candidate;
4152 }
4153
4154 pr_debug("Reusing \"%s\" BPF sys_enter augmenter for \"%s\"\n", pair->name,
4155 sc->name);
4156 return pair_prog;
4157 next_candidate:
4158 continue;
4159 }
4160
4161 return NULL;
4162}
4163
4164static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace, int e_machine)
4165{
4166 int map_enter_fd;
4167 int map_exit_fd;
4168 int beauty_map_fd;
4169 int err = 0;
4170 unsigned int beauty_array[6];
4171
4172 if (augmented_syscalls__get_map_fds(&map_enter_fd, &map_exit_fd, &beauty_map_fd) < 0)
4173 return -1;
4174
4175 unaugmented_prog = augmented_syscalls__unaugmented();
4176
4177 for (int i = 0, num_idx = syscalltbl__num_idx(e_machine); i < num_idx; ++i) {
4178 int prog_fd, key = syscalltbl__id_at_idx(e_machine, i);
4179
4180 if (!trace__syscall_enabled(trace, key))
4181 continue;
4182
4183 trace__init_syscall_bpf_progs(trace, e_machine, key);
4184
4185 // It'll get at least the "!raw_syscalls:unaugmented"
4186 prog_fd = trace__bpf_prog_sys_enter_fd(trace, e_machine, key);
4187 err = bpf_map_update_elem(map_enter_fd, &key, &prog_fd, BPF_ANY);
4188 if (err)
4189 break;
4190 prog_fd = trace__bpf_prog_sys_exit_fd(trace, e_machine, key);
4191 err = bpf_map_update_elem(map_exit_fd, &key, &prog_fd, BPF_ANY);
4192 if (err)
4193 break;
4194
4195 /* use beauty_map to tell BPF how many bytes to collect, set beauty_map's value here */
4196 memset(beauty_array, 0, sizeof(beauty_array));
4197 err = trace__bpf_sys_enter_beauty_map(trace, e_machine, key, (unsigned int *)beauty_array);
4198 if (err)
4199 continue;
4200 err = bpf_map_update_elem(beauty_map_fd, &key, beauty_array, BPF_ANY);
4201 if (err)
4202 break;
4203 }
4204
4205 /*
4206 * Now lets do a second pass looking for enabled syscalls without
4207 * an augmenter that have a signature that is a superset of another
4208 * syscall with an augmenter so that we can auto-reuse it.
4209 *
4210 * I.e. if we have an augmenter for the "open" syscall that has
4211 * this signature:
4212 *
4213 * int open(const char *pathname, int flags, mode_t mode);
4214 *
4215 * I.e. that will collect just the first string argument, then we
4216 * can reuse it for the 'creat' syscall, that has this signature:
4217 *
4218 * int creat(const char *pathname, mode_t mode);
4219 *
4220 * and for:
4221 *
4222 * int stat(const char *pathname, struct stat *statbuf);
4223 * int lstat(const char *pathname, struct stat *statbuf);
4224 *
4225 * Because the 'open' augmenter will collect the first arg as a string,
4226 * and leave alone all the other args, which already helps with
4227 * beautifying 'stat' and 'lstat''s pathname arg.
4228 *
4229 * Then, in time, when 'stat' gets an augmenter that collects both
4230 * first and second arg (this one on the raw_syscalls:sys_exit prog
4231 * array tail call, then that one will be used.
4232 */
4233 for (int i = 0, num_idx = syscalltbl__num_idx(e_machine); i < num_idx; ++i) {
4234 int key = syscalltbl__id_at_idx(e_machine, i);
4235 struct syscall *sc = trace__syscall_info(trace, NULL, e_machine, key);
4236 struct bpf_program *pair_prog;
4237 int prog_fd;
4238
4239 if (sc == NULL || sc->bpf_prog.sys_enter == NULL)
4240 continue;
4241
4242 /*
4243 * For now we're just reusing the sys_enter prog, and if it
4244 * already has an augmenter, we don't need to find one.
4245 */
4246 if (sc->bpf_prog.sys_enter != unaugmented_prog)
4247 continue;
4248
4249 /*
4250 * Look at all the other syscalls for one that has a signature
4251 * that is close enough that we can share:
4252 */
4253 pair_prog = trace__find_usable_bpf_prog_entry(trace, sc);
4254 if (pair_prog == NULL)
4255 continue;
4256
4257 sc->bpf_prog.sys_enter = pair_prog;
4258
4259 /*
4260 * Update the BPF_MAP_TYPE_PROG_SHARED for raw_syscalls:sys_enter
4261 * with the fd for the program we're reusing:
4262 */
4263 prog_fd = bpf_program__fd(sc->bpf_prog.sys_enter);
4264 err = bpf_map_update_elem(map_enter_fd, &key, &prog_fd, BPF_ANY);
4265 if (err)
4266 break;
4267 }
4268
4269 return err;
4270}
4271#else // !HAVE_LIBBPF_SUPPORT
4272static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace __maybe_unused,
4273 int e_machine __maybe_unused)
4274{
4275 return -1;
4276}
4277#endif // HAVE_LIBBPF_SUPPORT
4278
4279static int trace__set_ev_qualifier_filter(struct trace *trace)
4280{
4281 if (trace->syscalls.events.sys_enter)
4282 return trace__set_ev_qualifier_tp_filter(trace);
4283 return 0;
4284}
4285
4286static int trace__set_filter_loop_pids(struct trace *trace)
4287{
4288 unsigned int nr = 1, err;
4289 pid_t pids[32] = {
4290 getpid(),
4291 };
4292 struct thread *thread = machine__find_thread(trace->host, pids[0], pids[0]);
4293
4294 while (thread && nr < ARRAY_SIZE(pids)) {
4295 struct thread *parent = machine__find_thread(trace->host,
4296 thread__ppid(thread),
4297 thread__ppid(thread));
4298
4299 if (parent == NULL)
4300 break;
4301
4302 if (!strcmp(thread__comm_str(parent), "sshd") ||
4303 strstarts(thread__comm_str(parent), "gnome-terminal")) {
4304 pids[nr++] = thread__tid(parent);
4305 thread__put(parent);
4306 break;
4307 }
4308 thread__put(thread);
4309 thread = parent;
4310 }
4311 thread__put(thread);
4312
4313 err = evlist__append_tp_filter_pids(trace->evlist, nr, pids);
4314 if (!err)
4315 err = augmented_syscalls__set_filter_pids(nr, pids);
4316
4317 return err;
4318}
4319
4320static int trace__set_filter_pids(struct trace *trace)
4321{
4322 int err = 0;
4323 /*
4324 * Better not use !target__has_task() here because we need to cover the
4325 * case where no threads were specified in the command line, but a
4326 * workload was, and in that case we will fill in the thread_map when
4327 * we fork the workload in evlist__prepare_workload.
4328 */
4329 if (trace->filter_pids.nr > 0) {
4330 err = evlist__append_tp_filter_pids(trace->evlist, trace->filter_pids.nr,
4331 trace->filter_pids.entries);
4332 if (!err) {
4333 err = augmented_syscalls__set_filter_pids(trace->filter_pids.nr,
4334 trace->filter_pids.entries);
4335 }
4336 } else if (perf_thread_map__pid(evlist__core(trace->evlist)->threads, 0) == -1) {
4337 err = trace__set_filter_loop_pids(trace);
4338 }
4339
4340 return err;
4341}
4342
4343static int __trace__deliver_event(struct trace *trace, union perf_event *event)
4344{
4345 struct evlist *evlist = trace->evlist;
4346 struct perf_sample sample;
4347 int err;
4348
4349 perf_sample__init(&sample, /*all=*/false);
4350 err = evlist__parse_sample(evlist, event, &sample);
4351 if (err)
4352 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
4353 else
4354 trace__handle_event(trace, event, &sample);
4355
4356 perf_sample__exit(&sample);
4357 return 0;
4358}
4359
4360static int __trace__flush_events(struct trace *trace)
4361{
4362 u64 first = ordered_events__first_time(&trace->oe.data);
4363 u64 flush = trace->oe.last - NSEC_PER_SEC;
4364
4365 /* Is there some thing to flush.. */
4366 if (first && first < flush)
4367 return ordered_events__flush_time(&trace->oe.data, flush);
4368
4369 return 0;
4370}
4371
4372static int trace__flush_events(struct trace *trace)
4373{
4374 return !trace->sort_events ? 0 : __trace__flush_events(trace);
4375}
4376
4377static int trace__deliver_event(struct trace *trace, union perf_event *event)
4378{
4379 int err;
4380
4381 if (!trace->sort_events)
4382 return __trace__deliver_event(trace, event);
4383
4384 err = evlist__parse_sample_timestamp(trace->evlist, event, &trace->oe.last);
4385 if (err && err != -1)
4386 return err;
4387
4388 err = ordered_events__queue(&trace->oe.data, event, trace->oe.last, 0, NULL);
4389 if (err)
4390 return err;
4391
4392 return trace__flush_events(trace);
4393}
4394
4395static int ordered_events__deliver_event(struct ordered_events *oe,
4396 struct ordered_event *event)
4397{
4398 struct trace *trace = container_of(oe, struct trace, oe.data);
4399
4400 return __trace__deliver_event(trace, event->event);
4401}
4402
4403static struct syscall_arg_fmt *evsel__find_syscall_arg_fmt_by_name(struct evsel *evsel, char *arg,
4404 char **type)
4405{
4406 struct syscall_arg_fmt *fmt = __evsel__syscall_arg_fmt(evsel);
4407 const struct tep_event *tp_format;
4408
4409 if (!fmt)
4410 return NULL;
4411
4412 tp_format = evsel__tp_format(evsel);
4413 if (!tp_format)
4414 return NULL;
4415
4416 for (const struct tep_format_field *field = tp_format->format.fields; field;
4417 field = field->next, ++fmt) {
4418 if (strcmp(field->name, arg) == 0) {
4419 *type = field->type;
4420 return fmt;
4421 }
4422 }
4423
4424 return NULL;
4425}
4426
4427static int trace__expand_filter(struct trace *trace, struct evsel *evsel)
4428{
4429 char *tok, *left = evsel->filter, *new_filter = evsel->filter;
4430
4431 while ((tok = strpbrk(left, "=<>!")) != NULL) {
4432 char *right = tok + 1, *right_end;
4433
4434 if (*right == '=')
4435 ++right;
4436
4437 while (isspace(*right))
4438 ++right;
4439
4440 if (*right == '\0')
4441 break;
4442
4443 while (!isalpha(*left))
4444 if (++left == tok) {
4445 /*
4446 * Bail out, can't find the name of the argument that is being
4447 * used in the filter, let it try to set this filter, will fail later.
4448 */
4449 return 0;
4450 }
4451
4452 right_end = right + 1;
4453 while (isalnum(*right_end) || *right_end == '_' || *right_end == '|')
4454 ++right_end;
4455
4456 if (isalpha(*right)) {
4457 struct syscall_arg_fmt *fmt;
4458 int left_size = tok - left,
4459 right_size = right_end - right;
4460 char arg[128], *type;
4461
4462 while (isspace(left[left_size - 1]))
4463 --left_size;
4464
4465 scnprintf(arg, sizeof(arg), "%.*s", left_size, left);
4466
4467 fmt = evsel__find_syscall_arg_fmt_by_name(evsel, arg, &type);
4468 if (fmt == NULL) {
4469 pr_err("\"%s\" not found in \"%s\", can't set filter \"%s\"\n",
4470 arg, evsel->name, evsel->filter);
4471 return -1;
4472 }
4473
4474 pr_debug2("trying to expand \"%s\" \"%.*s\" \"%.*s\" -> ",
4475 arg, (int)(right - tok), tok, right_size, right);
4476
4477 if (fmt->strtoul) {
4478 u64 val;
4479 struct syscall_arg syscall_arg = {
4480 .trace = trace,
4481 .fmt = fmt,
4482 .type_name = type,
4483 .parm = fmt->parm,
4484 };
4485
4486 if (fmt->strtoul(right, right_size, &syscall_arg, &val)) {
4487 char *n, expansion[19];
4488 int expansion_lenght = scnprintf(expansion, sizeof(expansion), "%#" PRIx64, val);
4489 int expansion_offset = right - new_filter;
4490
4491 pr_debug("%s", expansion);
4492
4493 if (asprintf(&n, "%.*s%s%s", expansion_offset, new_filter, expansion, right_end) < 0) {
4494 pr_debug(" out of memory!\n");
4495 free(new_filter);
4496 return -1;
4497 }
4498 if (new_filter != evsel->filter)
4499 free(new_filter);
4500 left = n + expansion_offset + expansion_lenght;
4501 new_filter = n;
4502 } else {
4503 pr_err("\"%.*s\" not found for \"%s\" in \"%s\", can't set filter \"%s\"\n",
4504 right_size, right, arg, evsel->name, evsel->filter);
4505 return -1;
4506 }
4507 } else {
4508 pr_err("No resolver (strtoul) for \"%s\" in \"%s\", can't set filter \"%s\"\n",
4509 arg, evsel->name, evsel->filter);
4510 return -1;
4511 }
4512
4513 pr_debug("\n");
4514 } else {
4515 left = right_end;
4516 }
4517 }
4518
4519 if (new_filter != evsel->filter) {
4520 pr_debug("New filter for %s: %s\n", evsel->name, new_filter);
4521 evsel__set_filter(evsel, new_filter);
4522 free(new_filter);
4523 }
4524
4525 return 0;
4526}
4527
4528static int trace__expand_filters(struct trace *trace, struct evsel **err_evsel)
4529{
4530 struct evlist *evlist = trace->evlist;
4531 struct evsel *evsel;
4532
4533 evlist__for_each_entry(evlist, evsel) {
4534 if (evsel->filter == NULL)
4535 continue;
4536
4537 if (trace__expand_filter(trace, evsel)) {
4538 *err_evsel = evsel;
4539 return -1;
4540 }
4541 }
4542
4543 return 0;
4544}
4545
4546static int trace__run(struct trace *trace, int argc, const char **argv)
4547{
4548 struct evlist *evlist = trace->evlist;
4549 struct evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
4550 int err = -1, i;
4551 unsigned long before;
4552 const bool forks = argc > 0;
4553 bool draining = false;
4554
4555 trace->live = true;
4556
4557 if (trace->summary_bpf) {
4558 if (trace_prepare_bpf_summary(trace->summary_mode) < 0)
4559 goto out_put_evlist;
4560
4561 if (trace->summary_only)
4562 goto create_maps;
4563 }
4564
4565 if (!trace->raw_augmented_syscalls) {
4566 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
4567 goto out_error_raw_syscalls;
4568
4569 if (trace->trace_syscalls)
4570 trace->vfs_getname = evlist__add_vfs_getname(evlist);
4571 }
4572
4573 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
4574 pgfault_maj = evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
4575 if (pgfault_maj == NULL)
4576 goto out_error_mem;
4577 evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
4578 evlist__add(evlist, pgfault_maj);
4579 }
4580
4581 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
4582 pgfault_min = evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
4583 if (pgfault_min == NULL)
4584 goto out_error_mem;
4585 evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
4586 evlist__add(evlist, pgfault_min);
4587 }
4588
4589 /* Enable ignoring missing threads when -p option is defined. */
4590 trace->opts.ignore_missing_thread = trace->opts.target.pid;
4591
4592 if (trace->sched &&
4593 evlist__add_newtp(evlist, "sched", "sched_stat_runtime", trace__sched_stat_runtime))
4594 goto out_error_sched_stat_runtime;
4595 /*
4596 * If a global cgroup was set, apply it to all the events without an
4597 * explicit cgroup. I.e.:
4598 *
4599 * trace -G A -e sched:*switch
4600 *
4601 * Will set all raw_syscalls:sys_{enter,exit}, pgfault, vfs_getname, etc
4602 * _and_ sched:sched_switch to the 'A' cgroup, while:
4603 *
4604 * trace -e sched:*switch -G A
4605 *
4606 * will only set the sched:sched_switch event to the 'A' cgroup, all the
4607 * other events (raw_syscalls:sys_{enter,exit}, etc are left "without"
4608 * a cgroup (on the root cgroup, sys wide, etc).
4609 *
4610 * Multiple cgroups:
4611 *
4612 * trace -G A -e sched:*switch -G B
4613 *
4614 * the syscall ones go to the 'A' cgroup, the sched:sched_switch goes
4615 * to the 'B' cgroup.
4616 *
4617 * evlist__set_default_cgroup() grabs a reference of the passed cgroup
4618 * only for the evsels still without a cgroup, i.e. evsel->cgroup == NULL.
4619 */
4620 if (trace->cgroup)
4621 evlist__set_default_cgroup(trace->evlist, trace->cgroup);
4622
4623create_maps:
4624 err = evlist__create_maps(evlist, &trace->opts.target);
4625 if (err < 0) {
4626 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
4627 goto out_put_evlist;
4628 }
4629
4630 err = trace__symbols_init(trace, argc, argv, evlist);
4631 if (err < 0) {
4632 fprintf(trace->output, "Problems initializing symbol libraries!\n");
4633 goto out_put_evlist;
4634 }
4635
4636 if (trace->summary_mode == SUMMARY__BY_TOTAL && !trace->summary_bpf) {
4637 trace->syscall_stats = alloc_syscall_stats();
4638 if (!trace->syscall_stats)
4639 goto out_put_evlist;
4640 }
4641
4642 evlist__config(evlist, &trace->opts, &callchain_param);
4643
4644 if (forks) {
4645 err = evlist__prepare_workload(evlist, &trace->opts.target, argv, false, NULL);
4646 if (err < 0) {
4647 fprintf(trace->output, "Couldn't run the workload!\n");
4648 goto out_put_evlist;
4649 }
4650 workload_pid = evlist__workload_pid(evlist);
4651 }
4652
4653 err = evlist__open(evlist);
4654 if (err < 0)
4655 goto out_error_open;
4656
4657 augmented_syscalls__setup_bpf_output();
4658
4659 err = trace__set_filter_pids(trace);
4660 if (err < 0)
4661 goto out_error_mem;
4662
4663 /*
4664 * TODO: Initialize for all host binary machine types, not just
4665 * those matching the perf binary.
4666 */
4667 trace__init_syscalls_bpf_prog_array_maps(trace, EM_HOST);
4668
4669 if (trace->ev_qualifier_ids.nr > 0) {
4670 err = trace__set_ev_qualifier_filter(trace);
4671 if (err < 0)
4672 goto out_errno;
4673
4674 if (trace->syscalls.events.sys_exit) {
4675 pr_debug("event qualifier tracepoint filter: %s\n",
4676 trace->syscalls.events.sys_exit->filter);
4677 }
4678 }
4679
4680 /*
4681 * If the "close" syscall is not traced, then we will not have the
4682 * opportunity to, in syscall_arg__scnprintf_close_fd() invalidate the
4683 * fd->pathname table and were ending up showing the last value set by
4684 * syscalls opening a pathname and associating it with a descriptor or
4685 * reading it from /proc/pid/fd/ in cases where that doesn't make
4686 * sense.
4687 *
4688 * So just disable this beautifier (SCA_FD, SCA_FDAT) when 'close' is
4689 * not in use.
4690 */
4691 /* TODO: support for more than just perf binary machine type close. */
4692 trace->fd_path_disabled = !trace__syscall_enabled(trace, syscalltbl__id(EM_HOST, "close"));
4693
4694 err = trace__expand_filters(trace, &evsel);
4695 if (err)
4696 goto out_put_evlist;
4697 err = evlist__apply_filters(evlist, &evsel, &trace->opts.target);
4698 if (err < 0)
4699 goto out_error_apply_filters;
4700
4701 if (!trace->summary_only || !trace->summary_bpf) {
4702 err = evlist__do_mmap(evlist, trace->opts.mmap_pages);
4703 if (err < 0)
4704 goto out_error_mmap;
4705 }
4706
4707 if (!target__none(&trace->opts.target) && !trace->opts.target.initial_delay)
4708 evlist__enable(evlist);
4709
4710 if (forks)
4711 evlist__start_workload(evlist);
4712
4713 if (trace->opts.target.initial_delay) {
4714 usleep(trace->opts.target.initial_delay * 1000);
4715 evlist__enable(evlist);
4716 }
4717
4718 if (trace->summary_bpf)
4719 trace_start_bpf_summary();
4720
4721 trace->multiple_threads = perf_thread_map__pid(evlist__core(evlist)->threads, 0) == -1 ||
4722 perf_thread_map__nr(evlist__core(evlist)->threads) > 1 ||
4723 evlist__first(evlist)->core.attr.inherit;
4724
4725 /*
4726 * Now that we already used evsel->core.attr to ask the kernel to setup the
4727 * events, lets reuse evsel->core.attr.sample_max_stack as the limit in
4728 * trace__resolve_callchain(), allowing per-event max-stack settings
4729 * to override an explicitly set --max-stack global setting.
4730 */
4731 evlist__for_each_entry(evlist, evsel) {
4732 if (evsel__has_callchain(evsel) &&
4733 evsel->core.attr.sample_max_stack == 0)
4734 evsel->core.attr.sample_max_stack = trace->max_stack;
4735 }
4736again:
4737 before = trace->nr_events;
4738
4739 for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) {
4740 union perf_event *event;
4741 struct mmap *md;
4742
4743 md = &evlist__mmap(evlist)[i];
4744 if (perf_mmap__read_init(&md->core) < 0)
4745 continue;
4746
4747 while ((event = perf_mmap__read_event(&md->core)) != NULL) {
4748 ++trace->nr_events;
4749
4750 err = trace__deliver_event(trace, event);
4751 if (err)
4752 goto out_disable;
4753
4754 perf_mmap__consume(&md->core);
4755
4756 if (interrupted)
4757 goto out_disable;
4758
4759 if (done && !draining) {
4760 evlist__disable(evlist);
4761 draining = true;
4762 }
4763 }
4764 perf_mmap__read_done(&md->core);
4765 }
4766
4767 if (trace->nr_events == before) {
4768 int timeout = done ? 100 : -1;
4769
4770 if (!draining && evlist__poll(evlist, timeout) > 0) {
4771 if (evlist__filter_pollfd(evlist, POLLERR | POLLHUP | POLLNVAL) == 0)
4772 draining = true;
4773
4774 goto again;
4775 } else {
4776 if (trace__flush_events(trace))
4777 goto out_disable;
4778 }
4779 } else {
4780 goto again;
4781 }
4782
4783out_disable:
4784 thread__zput(trace->current);
4785
4786 evlist__disable(evlist);
4787
4788 if (trace->summary_bpf)
4789 trace_end_bpf_summary();
4790
4791 if (trace->sort_events)
4792 ordered_events__flush(&trace->oe.data, OE_FLUSH__FINAL);
4793
4794 if (!err) {
4795 if (trace->summary) {
4796 if (trace->summary_bpf)
4797 trace_print_bpf_summary(trace->output, trace->max_summary);
4798 else if (trace->summary_mode == SUMMARY__BY_TOTAL)
4799 trace__fprintf_total_summary(trace, trace->output);
4800 else
4801 trace__fprintf_thread_summary(trace, trace->output);
4802 }
4803
4804 if (trace->show_tool_stats) {
4805 fprintf(trace->output, "Stats:\n "
4806 " vfs_getname : %" PRIu64 "\n"
4807 " proc_getname: %" PRIu64 "\n",
4808 trace->stats.vfs_getname,
4809 trace->stats.proc_getname);
4810 }
4811 }
4812
4813out_put_evlist:
4814 trace_cleanup_bpf_summary();
4815 delete_syscall_stats(trace->syscall_stats);
4816 trace__symbols__exit(trace);
4817 evlist__free_syscall_tp_fields(evlist);
4818 evlist__put(evlist);
4819 cgroup__put(trace->cgroup);
4820 trace->evlist = NULL;
4821 trace->live = false;
4822 return err;
4823{
4824 char errbuf[BUFSIZ];
4825
4826out_error_sched_stat_runtime:
4827 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
4828 goto out_error;
4829
4830out_error_raw_syscalls:
4831 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
4832 goto out_error;
4833
4834out_error_mmap:
4835 evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
4836 goto out_error;
4837
4838out_error_open:
4839 evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
4840
4841out_error:
4842 fprintf(trace->output, "%s\n", errbuf);
4843 goto out_put_evlist;
4844
4845out_error_apply_filters:
4846 fprintf(trace->output,
4847 "Failed to set filter \"%s\" on event %s: %m\n",
4848 evsel->filter, evsel__name(evsel));
4849 goto out_put_evlist;
4850}
4851out_error_mem:
4852 fprintf(trace->output, "Not enough memory to run!\n");
4853 goto out_put_evlist;
4854
4855out_errno:
4856 fprintf(trace->output, "%m\n");
4857 goto out_put_evlist;
4858}
4859
4860static int trace__replay(struct trace *trace)
4861{
4862 const struct evsel_str_handler handlers[] = {
4863 { "probe:vfs_getname", trace__vfs_getname, },
4864 };
4865 struct perf_data data = {
4866 .path = input_name,
4867 .mode = PERF_DATA_MODE_READ,
4868 .force = trace->force,
4869 };
4870 struct perf_session *session;
4871 struct evsel *evsel;
4872 int err = -1;
4873
4874 perf_tool__init(&trace->tool, /*ordered_events=*/true);
4875 trace->tool.sample = trace__process_sample;
4876 trace->tool.mmap = perf_event__process_mmap;
4877 trace->tool.mmap2 = perf_event__process_mmap2;
4878 trace->tool.comm = perf_event__process_comm;
4879 trace->tool.exit = perf_event__process_exit;
4880 trace->tool.fork = perf_event__process_fork;
4881 trace->tool.attr = perf_event__process_attr;
4882 trace->tool.tracing_data = perf_event__process_tracing_data;
4883 trace->tool.build_id = perf_event__process_build_id;
4884 trace->tool.namespaces = perf_event__process_namespaces;
4885
4886 trace->tool.ordered_events = true;
4887 trace->tool.ordering_requires_timestamps = true;
4888
4889 /* add tid to output */
4890 trace->multiple_threads = true;
4891
4892 session = perf_session__new(&data, &trace->tool);
4893 if (IS_ERR(session))
4894 return PTR_ERR(session);
4895
4896 if (trace->opts.target.pid)
4897 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
4898
4899 if (trace->opts.target.tid)
4900 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
4901
4902 if (symbol__init(perf_session__env(session)) < 0)
4903 goto out;
4904
4905 trace->host = &session->machines.host;
4906
4907 err = perf_session__set_tracepoints_handlers(session, handlers);
4908 if (err)
4909 goto out;
4910
4911 evsel = evlist__find_tracepoint_by_name(session->evlist, "raw_syscalls:sys_enter");
4912 trace->syscalls.events.sys_enter = evsel;
4913 /* older kernels have syscalls tp versus raw_syscalls */
4914 if (evsel == NULL)
4915 evsel = evlist__find_tracepoint_by_name(session->evlist, "syscalls:sys_enter");
4916
4917 if (evsel &&
4918 (evsel__init_raw_syscall_tp(evsel, trace__sys_enter) < 0 ||
4919 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
4920 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
4921 goto out;
4922 }
4923
4924 evsel = evlist__find_tracepoint_by_name(session->evlist, "raw_syscalls:sys_exit");
4925 trace->syscalls.events.sys_exit = evsel;
4926 if (evsel == NULL)
4927 evsel = evlist__find_tracepoint_by_name(session->evlist, "syscalls:sys_exit");
4928 if (evsel &&
4929 (evsel__init_raw_syscall_tp(evsel, trace__sys_exit) < 0 ||
4930 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
4931 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
4932 goto out;
4933 }
4934
4935 evlist__for_each_entry(session->evlist, evsel) {
4936 if (evsel->core.attr.type == PERF_TYPE_SOFTWARE &&
4937 (evsel->core.attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
4938 evsel->core.attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
4939 evsel->core.attr.config == PERF_COUNT_SW_PAGE_FAULTS))
4940 evsel->handler = trace__pgfault;
4941 }
4942
4943 if (trace->summary_mode == SUMMARY__BY_TOTAL) {
4944 trace->syscall_stats = alloc_syscall_stats();
4945 if (!trace->syscall_stats)
4946 goto out;
4947 }
4948
4949 setup_pager();
4950
4951 err = perf_session__process_events(session);
4952 if (err)
4953 pr_err("Failed to process events, error %d", err);
4954
4955 else if (trace->summary)
4956 trace__fprintf_thread_summary(trace, trace->output);
4957
4958out:
4959 delete_syscall_stats(trace->syscall_stats);
4960 perf_session__delete(session);
4961
4962 return err;
4963}
4964
4965static size_t trace__fprintf_summary_header(FILE *fp)
4966{
4967 size_t printed;
4968
4969 printed = fprintf(fp, "\n Summary of events:\n\n");
4970
4971 return printed;
4972}
4973
4974struct syscall_entry {
4975 struct syscall_stats *stats;
4976 double msecs;
4977 int syscall;
4978};
4979
4980static int entry_cmp(const void *e1, const void *e2)
4981{
4982 const struct syscall_entry *entry1 = e1;
4983 const struct syscall_entry *entry2 = e2;
4984
4985 return entry1->msecs > entry2->msecs ? -1 : 1;
4986}
4987
4988static struct syscall_entry *syscall__sort_stats(struct hashmap *syscall_stats)
4989{
4990 struct syscall_entry *entry;
4991 struct hashmap_entry *pos;
4992 unsigned bkt, i, nr;
4993
4994 nr = syscall_stats->sz;
4995 entry = malloc(nr * sizeof(*entry));
4996 if (entry == NULL)
4997 return NULL;
4998
4999 i = 0;
5000 hashmap__for_each_entry(syscall_stats, pos, bkt) {
5001 struct syscall_stats *ss = pos->pvalue;
5002 struct stats *st = &ss->stats;
5003
5004 entry[i].stats = ss;
5005 entry[i].msecs = (u64)st->n * (avg_stats(st) / NSEC_PER_MSEC);
5006 entry[i].syscall = pos->key;
5007 i++;
5008 }
5009 assert(i == nr);
5010
5011 qsort(entry, nr, sizeof(*entry), entry_cmp);
5012 return entry;
5013}
5014
5015static size_t syscall__dump_stats(struct trace *trace, int e_machine, FILE *fp,
5016 struct hashmap *syscall_stats)
5017{
5018 size_t printed = 0;
5019 int lines = 0;
5020 struct syscall *sc;
5021 struct syscall_entry *entries;
5022
5023 entries = syscall__sort_stats(syscall_stats);
5024 if (entries == NULL)
5025 return 0;
5026
5027 printed += fprintf(fp, "\n");
5028
5029 printed += fprintf(fp, " syscall calls errors total min avg max stddev\n");
5030 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
5031 printed += fprintf(fp, " --------------- -------- ------ -------- --------- --------- --------- ------\n");
5032
5033 for (size_t i = 0; i < syscall_stats->sz; i++) {
5034 struct syscall_entry *entry = &entries[i];
5035 struct syscall_stats *stats = entry->stats;
5036
5037 if (stats) {
5038 double min = (double)(stats->stats.min) / NSEC_PER_MSEC;
5039 double max = (double)(stats->stats.max) / NSEC_PER_MSEC;
5040 double avg = avg_stats(&stats->stats);
5041 double pct;
5042 u64 n = (u64)stats->stats.n;
5043
5044 pct = avg ? 100.0 * stddev_stats(&stats->stats) / avg : 0.0;
5045 avg /= NSEC_PER_MSEC;
5046
5047 sc = trace__syscall_info(trace, /*evsel=*/NULL, e_machine, entry->syscall);
5048 if (!sc)
5049 continue;
5050
5051 printed += fprintf(fp, " %-15s", sc->name);
5052 printed += fprintf(fp, " %8" PRIu64 " %6" PRIu64 " %9.3f %9.3f %9.3f",
5053 n, stats->nr_failures, entry->msecs, min, avg);
5054 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
5055
5056 if (trace->errno_summary && stats->nr_failures) {
5057 int e;
5058
5059 for (e = 0; e < stats->max_errno; ++e) {
5060 if (stats->errnos[e] != 0)
5061 fprintf(fp, "\t\t\t\t%s: %d\n",
5062 perf_env__arch_strerrno(e_machine, e + 1),
5063 stats->errnos[e]);
5064 }
5065 }
5066 lines++;
5067 }
5068
5069 if (trace->max_summary && trace->max_summary <= lines)
5070 break;
5071 }
5072
5073 free(entries);
5074 printed += fprintf(fp, "\n\n");
5075
5076 return printed;
5077}
5078
5079static size_t thread__dump_stats(struct thread_trace *ttrace,
5080 struct trace *trace, int e_machine, FILE *fp)
5081{
5082 return syscall__dump_stats(trace, e_machine, fp, ttrace->syscall_stats);
5083}
5084
5085static size_t system__dump_stats(struct trace *trace, int e_machine, FILE *fp)
5086{
5087 return syscall__dump_stats(trace, e_machine, fp, trace->syscall_stats);
5088}
5089
5090static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
5091{
5092 size_t printed = 0;
5093 struct thread_trace *ttrace = thread__priv(thread);
5094 int e_machine = thread__e_machine(thread, trace->host, /*e_flags=*/NULL);
5095 double ratio;
5096
5097 if (ttrace == NULL)
5098 return 0;
5099
5100 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
5101
5102 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread__tid(thread));
5103 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
5104 printed += fprintf(fp, "%.1f%%", ratio);
5105 if (ttrace->pfmaj)
5106 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
5107 if (ttrace->pfmin)
5108 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
5109 if (trace->sched)
5110 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
5111 else if (fputc('\n', fp) != EOF)
5112 ++printed;
5113
5114 printed += thread__dump_stats(ttrace, trace, e_machine, fp);
5115
5116 return printed;
5117}
5118
5119static unsigned long thread__nr_events(struct thread_trace *ttrace)
5120{
5121 return ttrace ? ttrace->nr_events : 0;
5122}
5123
5124static int trace_nr_events_cmp(void *priv __maybe_unused,
5125 const struct list_head *la,
5126 const struct list_head *lb)
5127{
5128 struct thread_list *a = list_entry(la, struct thread_list, list);
5129 struct thread_list *b = list_entry(lb, struct thread_list, list);
5130 unsigned long a_nr_events = thread__nr_events(thread__priv(a->thread));
5131 unsigned long b_nr_events = thread__nr_events(thread__priv(b->thread));
5132
5133 if (a_nr_events != b_nr_events)
5134 return a_nr_events < b_nr_events ? -1 : 1;
5135
5136 /* Identical number of threads, place smaller tids first. */
5137 return thread__tid(a->thread) < thread__tid(b->thread)
5138 ? -1
5139 : (thread__tid(a->thread) > thread__tid(b->thread) ? 1 : 0);
5140}
5141
5142static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
5143{
5144 size_t printed = trace__fprintf_summary_header(fp);
5145 LIST_HEAD(threads);
5146
5147 if (machine__thread_list(trace->host, &threads) == 0) {
5148 struct thread_list *pos;
5149
5150 list_sort(NULL, &threads, trace_nr_events_cmp);
5151
5152 list_for_each_entry(pos, &threads, list)
5153 printed += trace__fprintf_thread(fp, pos->thread, trace);
5154 }
5155 thread_list__delete(&threads);
5156 return printed;
5157}
5158
5159static size_t trace__fprintf_total_summary(struct trace *trace, FILE *fp)
5160{
5161 size_t printed = trace__fprintf_summary_header(fp);
5162
5163 printed += fprintf(fp, " total, ");
5164 printed += fprintf(fp, "%lu events", trace->nr_events);
5165
5166 if (trace->pfmaj)
5167 printed += fprintf(fp, ", %lu majfaults", trace->pfmaj);
5168 if (trace->pfmin)
5169 printed += fprintf(fp, ", %lu minfaults", trace->pfmin);
5170 if (trace->sched)
5171 printed += fprintf(fp, ", %.3f msec\n", trace->runtime_ms);
5172 else if (fputc('\n', fp) != EOF)
5173 ++printed;
5174
5175 /* TODO: get all system e_machines. */
5176 printed += system__dump_stats(trace, EM_HOST, fp);
5177
5178 return printed;
5179}
5180
5181static int trace__set_duration(const struct option *opt, const char *str,
5182 int unset __maybe_unused)
5183{
5184 struct trace *trace = opt->value;
5185
5186 trace->duration_filter = atof(str);
5187 return 0;
5188}
5189
5190static int trace__set_filter_pids_from_option(const struct option *opt, const char *str,
5191 int unset __maybe_unused)
5192{
5193 int ret = -1;
5194 size_t i;
5195 struct trace *trace = opt->value;
5196 /*
5197 * FIXME: introduce a intarray class, plain parse csv and create a
5198 * { int nr, int entries[] } struct...
5199 */
5200 struct intlist *list = intlist__new(str);
5201
5202 if (list == NULL)
5203 return -1;
5204
5205 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
5206 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
5207
5208 if (trace->filter_pids.entries == NULL)
5209 goto out;
5210
5211 trace->filter_pids.entries[0] = getpid();
5212
5213 for (i = 1; i < trace->filter_pids.nr; ++i)
5214 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
5215
5216 intlist__delete(list);
5217 ret = 0;
5218out:
5219 return ret;
5220}
5221
5222static int trace__open_output(struct trace *trace, const char *filename)
5223{
5224 struct stat st;
5225
5226 if (!stat(filename, &st) && st.st_size) {
5227 char oldname[PATH_MAX];
5228
5229 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
5230 unlink(oldname);
5231 rename(filename, oldname);
5232 }
5233
5234 trace->output = fopen(filename, "w");
5235
5236 return trace->output == NULL ? -errno : 0;
5237}
5238
5239static int parse_pagefaults(const struct option *opt, const char *str,
5240 int unset __maybe_unused)
5241{
5242 int *trace_pgfaults = opt->value;
5243
5244 if (strcmp(str, "all") == 0)
5245 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
5246 else if (strcmp(str, "maj") == 0)
5247 *trace_pgfaults |= TRACE_PFMAJ;
5248 else if (strcmp(str, "min") == 0)
5249 *trace_pgfaults |= TRACE_PFMIN;
5250 else
5251 return -1;
5252
5253 return 0;
5254}
5255
5256static void evlist__set_default_evsel_handler(struct evlist *evlist, void *handler)
5257{
5258 struct evsel *evsel;
5259
5260 evlist__for_each_entry(evlist, evsel) {
5261 if (evsel->handler == NULL)
5262 evsel->handler = handler;
5263 }
5264}
5265
5266static void evsel__set_syscall_arg_fmt(struct evsel *evsel, const char *name)
5267{
5268 struct syscall_arg_fmt *fmt = evsel__syscall_arg_fmt(evsel);
5269
5270 if (fmt) {
5271 const struct syscall_fmt *scfmt = syscall_fmt__find(name);
5272
5273 if (scfmt) {
5274 const struct tep_event *tp_format = evsel__tp_format(evsel);
5275
5276 if (tp_format) {
5277 int skip = 0;
5278
5279 if (strcmp(tp_format->format.fields->name, "__syscall_nr") == 0 ||
5280 strcmp(tp_format->format.fields->name, "nr") == 0)
5281 ++skip;
5282
5283 memcpy(fmt + skip, scfmt->arg,
5284 (tp_format->format.nr_fields - skip) * sizeof(*fmt));
5285 }
5286 }
5287 }
5288}
5289
5290static int evlist__set_syscall_tp_fields(struct evlist *evlist, bool *use_btf)
5291{
5292 struct evsel *evsel;
5293
5294 evlist__for_each_entry(evlist, evsel) {
5295 const struct tep_event *tp_format;
5296
5297 if (evsel->priv)
5298 continue;
5299
5300 tp_format = evsel__tp_format(evsel);
5301 if (!tp_format)
5302 continue;
5303
5304 if (strcmp(tp_format->system, "syscalls")) {
5305 evsel__init_tp_arg_scnprintf(evsel, use_btf);
5306 continue;
5307 }
5308
5309 if (evsel__init_syscall_tp(evsel))
5310 return -1;
5311
5312 if (!strncmp(tp_format->name, "sys_enter_", 10)) {
5313 struct syscall_tp *sc = __evsel__syscall_tp(evsel);
5314
5315 if (__tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64)))
5316 return -1;
5317
5318 evsel__set_syscall_arg_fmt(evsel,
5319 tp_format->name + sizeof("sys_enter_") - 1);
5320 } else if (!strncmp(tp_format->name, "sys_exit_", 9)) {
5321 struct syscall_tp *sc = __evsel__syscall_tp(evsel);
5322
5323 if (__tp_field__init_uint(&sc->ret, sizeof(u64),
5324 sc->id.offset + sizeof(u64),
5325 evsel->needs_swap))
5326 return -1;
5327
5328 evsel__set_syscall_arg_fmt(evsel,
5329 tp_format->name + sizeof("sys_exit_") - 1);
5330 }
5331 }
5332
5333 return 0;
5334}
5335
5336/*
5337 * XXX: Hackish, just splitting the combined -e+--event (syscalls
5338 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
5339 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
5340 *
5341 * It'd be better to introduce a parse_options() variant that would return a
5342 * list with the terms it didn't match to an event...
5343 */
5344static int trace__parse_events_option(const struct option *opt, const char *str,
5345 int unset __maybe_unused)
5346{
5347 struct trace *trace = (struct trace *)opt->value;
5348 const char *s;
5349 char *strd, *sep = NULL, *lists[2] = { NULL, NULL, };
5350 int len = strlen(str) + 1, err = -1, list, idx;
5351 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
5352 char group_name[PATH_MAX];
5353 const struct syscall_fmt *fmt;
5354
5355 if (strace_groups_dir == NULL)
5356 return -1;
5357
5358 s = strd = strdup(str);
5359 if (strd == NULL)
5360 return -1;
5361
5362 if (*s == '!') {
5363 ++s;
5364 trace->not_ev_qualifier = true;
5365 }
5366
5367 while (1) {
5368 if ((sep = strchr((char *)s, ',')) != NULL)
5369 *sep = '\0';
5370
5371 list = 0;
5372 /* TODO: support for more than just perf binary machine type syscalls. */
5373 if (syscalltbl__id(EM_HOST, s) >= 0 ||
5374 syscalltbl__strglobmatch_first(EM_HOST, s, &idx) >= 0) {
5375 list = 1;
5376 goto do_concat;
5377 }
5378
5379 fmt = syscall_fmt__find_by_alias(s);
5380 if (fmt != NULL) {
5381 list = 1;
5382 s = fmt->name;
5383 } else {
5384 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
5385 if (access(group_name, R_OK) == 0)
5386 list = 1;
5387 }
5388do_concat:
5389 if (lists[list]) {
5390 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
5391 } else {
5392 lists[list] = malloc(len);
5393 if (lists[list] == NULL)
5394 goto out;
5395 strcpy(lists[list], s);
5396 }
5397
5398 if (!sep)
5399 break;
5400
5401 *sep = ',';
5402 s = sep + 1;
5403 }
5404
5405 if (lists[1] != NULL) {
5406 struct strlist_config slist_config = {
5407 .dirname = strace_groups_dir,
5408 };
5409
5410 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
5411 if (trace->ev_qualifier == NULL) {
5412 fputs("Not enough memory to parse event qualifier", trace->output);
5413 goto out;
5414 }
5415
5416 if (trace__validate_ev_qualifier(trace))
5417 goto out;
5418 trace->trace_syscalls = true;
5419 }
5420
5421 err = 0;
5422
5423 if (lists[0]) {
5424 struct parse_events_option_args parse_events_option_args = {
5425 .evlistp = &trace->evlist,
5426 };
5427 struct option o = {
5428 .value = &parse_events_option_args,
5429 };
5430 err = parse_events_option(&o, lists[0], 0);
5431 }
5432out:
5433 free(strace_groups_dir);
5434 free(lists[0]);
5435 free(lists[1]);
5436 free(strd);
5437
5438 return err;
5439}
5440
5441static int trace__parse_cgroups(const struct option *opt, const char *str, int unset)
5442{
5443 struct trace *trace = opt->value;
5444
5445 if (!list_empty(&evlist__core(trace->evlist)->entries)) {
5446 struct option o = {
5447 .value = &trace->evlist,
5448 };
5449 return parse_cgroups(&o, str, unset);
5450 }
5451 trace->cgroup = evlist__findnew_cgroup(trace->evlist, str);
5452
5453 return 0;
5454}
5455
5456static int trace__parse_summary_mode(const struct option *opt, const char *str,
5457 int unset __maybe_unused)
5458{
5459 struct trace *trace = opt->value;
5460
5461 if (!strcmp(str, "thread")) {
5462 trace->summary_mode = SUMMARY__BY_THREAD;
5463 } else if (!strcmp(str, "total")) {
5464 trace->summary_mode = SUMMARY__BY_TOTAL;
5465 } else if (!strcmp(str, "cgroup")) {
5466 trace->summary_mode = SUMMARY__BY_CGROUP;
5467 } else {
5468 pr_err("Unknown summary mode: %s\n", str);
5469 return -1;
5470 }
5471
5472 return 0;
5473}
5474
5475static int trace_parse_callchain_opt(const struct option *opt,
5476 const char *arg,
5477 int unset)
5478{
5479 return record_opts__parse_callchain(opt->value, &callchain_param, arg, unset);
5480}
5481
5482static int trace__config(const char *var, const char *value, void *arg)
5483{
5484 struct trace *trace = arg;
5485 int err = 0;
5486
5487 if (!strcmp(var, "trace.add_events")) {
5488 trace->perfconfig_events = strdup(value);
5489 if (trace->perfconfig_events == NULL) {
5490 pr_err("Not enough memory for %s\n", "trace.add_events");
5491 return -1;
5492 }
5493 } else if (!strcmp(var, "trace.show_timestamp")) {
5494 trace->show_tstamp = perf_config_bool(var, value);
5495 } else if (!strcmp(var, "trace.show_duration")) {
5496 trace->show_duration = perf_config_bool(var, value);
5497 } else if (!strcmp(var, "trace.show_arg_names")) {
5498 trace->show_arg_names = perf_config_bool(var, value);
5499 if (!trace->show_arg_names)
5500 trace->show_zeros = true;
5501 } else if (!strcmp(var, "trace.show_zeros")) {
5502 bool new_show_zeros = perf_config_bool(var, value);
5503 if (!trace->show_arg_names && !new_show_zeros) {
5504 pr_warning("trace.show_zeros has to be set when trace.show_arg_names=no\n");
5505 goto out;
5506 }
5507 trace->show_zeros = new_show_zeros;
5508 } else if (!strcmp(var, "trace.show_prefix")) {
5509 trace->show_string_prefix = perf_config_bool(var, value);
5510 } else if (!strcmp(var, "trace.no_inherit")) {
5511 trace->opts.no_inherit = perf_config_bool(var, value);
5512 } else if (!strcmp(var, "trace.args_alignment")) {
5513 int args_alignment = 0;
5514 if (perf_config_int(&args_alignment, var, value) == 0)
5515 trace->args_alignment = args_alignment;
5516 } else if (!strcmp(var, "trace.tracepoint_beautifiers")) {
5517 if (strcasecmp(value, "libtraceevent") == 0)
5518 trace->libtraceevent_print = true;
5519 else if (strcasecmp(value, "libbeauty") == 0)
5520 trace->libtraceevent_print = false;
5521 }
5522out:
5523 return err;
5524}
5525
5526static void trace__exit(struct trace *trace)
5527{
5528 thread__zput(trace->current);
5529 strlist__delete(trace->ev_qualifier);
5530 zfree(&trace->ev_qualifier_ids.entries);
5531 if (trace->syscalls.table) {
5532 for (size_t i = 0; i < trace->syscalls.table_size; i++)
5533 syscall__delete(trace->syscalls.table[i]);
5534 zfree(&trace->syscalls.table);
5535 }
5536 zfree(&trace->perfconfig_events);
5537 evlist__put(trace->evlist);
5538 trace->evlist = NULL;
5539 ordered_events__free(&trace->oe.data);
5540#ifdef HAVE_LIBBPF_SUPPORT
5541 btf__free(trace->btf);
5542 trace->btf = NULL;
5543#endif
5544}
5545
5546int cmd_trace(int argc, const char **argv)
5547{
5548 const char *trace_usage[] = {
5549 "perf trace [<options>] [<command>]",
5550 "perf trace [<options>] -- <command> [<options>]",
5551 "perf trace record [<options>] [<command>]",
5552 "perf trace record [<options>] -- <command> [<options>]",
5553 NULL
5554 };
5555 struct trace trace = {
5556 .opts = {
5557 .target = {
5558 .uses_mmap = true,
5559 },
5560 .user_freq = UINT_MAX,
5561 .user_interval = ULLONG_MAX,
5562 .no_buffering = true,
5563 .mmap_pages = UINT_MAX,
5564 },
5565 .output = stderr,
5566 .show_comm = true,
5567 .show_tstamp = true,
5568 .show_duration = true,
5569 .show_arg_names = true,
5570 .args_alignment = 70,
5571 .trace_syscalls = false,
5572 .kernel_syscallchains = false,
5573 .max_stack = UINT_MAX,
5574 .max_events = ULONG_MAX,
5575 };
5576 const char *output_name = NULL;
5577 const struct option trace_options[] = {
5578 OPT_CALLBACK('e', "event", &trace, "event",
5579 "event/syscall selector. use 'perf list' to list available events",
5580 trace__parse_events_option),
5581 OPT_CALLBACK(0, "filter", &trace.evlist, "filter",
5582 "event filter", parse_filter),
5583 OPT_BOOLEAN(0, "comm", &trace.show_comm,
5584 "show the thread COMM next to its id"),
5585 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
5586 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
5587 trace__parse_events_option),
5588 OPT_STRING('o', "output", &output_name, "file", "output file name"),
5589 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
5590 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
5591 "trace events on existing process id"),
5592 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
5593 "trace events on existing thread id"),
5594 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
5595 "pids to filter (by the kernel)", trace__set_filter_pids_from_option),
5596 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
5597 "system-wide collection from all CPUs"),
5598 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
5599 "list of cpus to monitor"),
5600 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
5601 "child tasks do not inherit counters"),
5602 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
5603 "number of mmap data pages", evlist__parse_mmap_pages),
5604 OPT_STRING('u', "uid", &trace.uid_str, "user", "user to profile"),
5605 OPT_BOOLEAN(0, "show-cpu", &trace.show_cpu, "show cpu id"),
5606 OPT_CALLBACK(0, "duration", &trace, "float",
5607 "show only events with duration > N.M ms",
5608 trace__set_duration),
5609 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
5610 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
5611 OPT_BOOLEAN('T', "time", &trace.full_time,
5612 "Show full timestamp, not time relative to first start"),
5613 OPT_BOOLEAN(0, "failure", &trace.failure_only,
5614 "Show only syscalls that failed"),
5615 OPT_BOOLEAN('s', "summary", &trace.summary_only,
5616 "Show only syscall summary with statistics"),
5617 OPT_BOOLEAN('S', "with-summary", &trace.summary,
5618 "Show all syscalls and summary with statistics"),
5619 OPT_BOOLEAN(0, "errno-summary", &trace.errno_summary,
5620 "Show errno stats per syscall, use with -s or -S"),
5621 OPT_CALLBACK(0, "summary-mode", &trace, "mode",
5622 "How to show summary: select thread (default), total or cgroup",
5623 trace__parse_summary_mode),
5624 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
5625 "Trace pagefaults", parse_pagefaults, "maj"),
5626 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
5627 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
5628 OPT_CALLBACK(0, "call-graph", &trace.opts,
5629 "record_mode[,record_size]", record_callchain_help,
5630 &trace_parse_callchain_opt),
5631 OPT_BOOLEAN(0, "libtraceevent_print", &trace.libtraceevent_print,
5632 "Use libtraceevent to print the tracepoint arguments."),
5633 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
5634 "Show the kernel callchains on the syscall exit path"),
5635 OPT_ULONG(0, "max-events", &trace.max_events,
5636 "Set the maximum number of events to print, exit after that is reached. "),
5637 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
5638 "Set the minimum stack depth when parsing the callchain, "
5639 "anything below the specified depth will be ignored."),
5640 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
5641 "Set the maximum stack depth when parsing the callchain, "
5642 "anything beyond the specified depth will be ignored. "
5643 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
5644 OPT_BOOLEAN(0, "sort-events", &trace.sort_events,
5645 "Sort batch of events before processing, use if getting out of order events"),
5646 OPT_BOOLEAN(0, "print-sample", &trace.print_sample,
5647 "print the PERF_RECORD_SAMPLE PERF_SAMPLE_ info, for debugging"),
5648 OPT_UINTEGER(0, "proc-map-timeout", &proc_map_timeout,
5649 "per thread proc mmap processing timeout in ms"),
5650 OPT_CALLBACK('G', "cgroup", &trace, "name", "monitor event in cgroup name only",
5651 trace__parse_cgroups),
5652 OPT_INTEGER('D', "delay", &trace.opts.target.initial_delay,
5653 "ms to wait before starting measurement after program "
5654 "start"),
5655 OPT_BOOLEAN(0, "force-btf", &trace.force_btf, "Prefer btf_dump general pretty printer"
5656 "to customized ones"),
5657 OPT_BOOLEAN(0, "bitmask-list", &trace.bitmask_list, "Show bitmask as a human-readable list"),
5658 OPT_BOOLEAN(0, "bpf-summary", &trace.summary_bpf, "Summary syscall stats in BPF"),
5659 OPT_INTEGER(0, "max-summary", &trace.max_summary,
5660 "Max number of entries in the summary."),
5661 OPTS_EVSWITCH(&trace.evswitch),
5662 OPT_END()
5663 };
5664 bool __maybe_unused max_stack_user_set = true;
5665 bool mmap_pages_user_set = true;
5666 struct evsel *evsel;
5667 const char * const trace_subcommands[] = { "record", NULL };
5668 int err = -1;
5669 char bf[BUFSIZ];
5670 struct sigaction sigchld_act;
5671
5672 signal(SIGSEGV, sighandler_dump_stack);
5673 signal(SIGFPE, sighandler_dump_stack);
5674 signal(SIGINT, sighandler_interrupt);
5675
5676 memset(&sigchld_act, 0, sizeof(sigchld_act));
5677 sigchld_act.sa_flags = SA_SIGINFO;
5678 sigchld_act.sa_sigaction = sighandler_chld;
5679 sigaction(SIGCHLD, &sigchld_act, NULL);
5680
5681 ordered_events__init(&trace.oe.data, ordered_events__deliver_event, &trace);
5682 ordered_events__set_copy_on_queue(&trace.oe.data, true);
5683
5684 trace.evlist = evlist__new();
5685
5686 if (trace.evlist == NULL) {
5687 pr_err("Not enough memory to run!\n");
5688 err = -ENOMEM;
5689 goto out;
5690 }
5691
5692 /*
5693 * Parsing .perfconfig may entail creating a BPF event, that may need
5694 * to create BPF maps, so bump RLIM_MEMLOCK as the default 64K setting
5695 * is too small. This affects just this process, not touching the
5696 * global setting. If it fails we'll get something in 'perf trace -v'
5697 * to help diagnose the problem.
5698 */
5699 rlimit__bump_memlock();
5700
5701 err = perf_config(trace__config, &trace);
5702 if (err)
5703 goto out;
5704
5705 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
5706 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
5707
5708 /*
5709 * Here we already passed thru trace__parse_events_option() and it has
5710 * already figured out if -e syscall_name, if not but if --event
5711 * foo:bar was used, the user is interested _just_ in those, say,
5712 * tracepoint events, not in the strace-like syscall-name-based mode.
5713 *
5714 * This is important because we need to check if strace-like mode is
5715 * needed to decided if we should filter out the eBPF
5716 * __augmented_syscalls__ code, if it is in the mix, say, via
5717 * .perfconfig trace.add_events, and filter those out.
5718 */
5719 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
5720 evlist__nr_entries(trace.evlist) == 0 /* Was --events used? */) {
5721 trace.trace_syscalls = true;
5722 }
5723 /*
5724 * Now that we have --verbose figured out, lets see if we need to parse
5725 * events from .perfconfig, so that if those events fail parsing, say some
5726 * BPF program fails, then we'll be able to use --verbose to see what went
5727 * wrong in more detail.
5728 */
5729 if (trace.perfconfig_events != NULL) {
5730 struct parse_events_error parse_err;
5731
5732 parse_events_error__init(&parse_err);
5733 err = parse_events(trace.evlist, trace.perfconfig_events, &parse_err);
5734 if (err)
5735 parse_events_error__print(&parse_err, trace.perfconfig_events);
5736 parse_events_error__exit(&parse_err);
5737 if (err)
5738 goto out;
5739 }
5740
5741 if (trace.show_cpu)
5742 trace.opts.sample_cpu = true;
5743
5744 if ((nr_cgroups || trace.cgroup) && !trace.opts.target.system_wide) {
5745 usage_with_options_msg(trace_usage, trace_options,
5746 "cgroup monitoring only available in system-wide mode");
5747 }
5748
5749 if (!trace.trace_syscalls)
5750 goto skip_augmentation;
5751
5752 if ((argc >= 1) && (strcmp(argv[0], "record") == 0)) {
5753 pr_debug("Syscall augmentation fails with record, disabling augmentation");
5754 goto skip_augmentation;
5755 }
5756
5757 if (trace.summary_bpf) {
5758 if (!trace.opts.target.system_wide) {
5759 /* TODO: Add filters in the BPF to support other targets. */
5760 pr_err("Error: --bpf-summary only works for system-wide mode.\n");
5761 goto out;
5762 }
5763 if (trace.summary_only)
5764 goto skip_augmentation;
5765 }
5766
5767 err = augmented_syscalls__prepare();
5768 if (err < 0)
5769 goto skip_augmentation;
5770
5771 trace__add_syscall_newtp(&trace);
5772
5773 err = augmented_syscalls__create_bpf_output(trace.evlist);
5774 if (err == 0)
5775 trace.syscalls.events.bpf_output = evlist__last(trace.evlist);
5776
5777skip_augmentation:
5778 err = -1;
5779
5780 if (trace.trace_pgfaults) {
5781 trace.opts.sample_address = true;
5782 trace.opts.sample_time = true;
5783 }
5784
5785 if (trace.opts.mmap_pages == UINT_MAX)
5786 mmap_pages_user_set = false;
5787
5788 if (trace.max_stack == UINT_MAX) {
5789 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl__max_stack();
5790 max_stack_user_set = false;
5791 }
5792
5793#ifdef HAVE_DWARF_UNWIND_SUPPORT
5794 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled) {
5795 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
5796 }
5797#endif
5798
5799 if (callchain_param.enabled) {
5800 if (!mmap_pages_user_set && geteuid() == 0)
5801 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
5802
5803 symbol_conf.use_callchain = true;
5804 }
5805
5806 if (evlist__nr_entries(trace.evlist) > 0) {
5807 bool use_btf = false;
5808
5809 evlist__set_default_evsel_handler(trace.evlist, trace__event_handler);
5810 if (evlist__set_syscall_tp_fields(trace.evlist, &use_btf)) {
5811 perror("failed to set syscalls:* tracepoint fields");
5812 goto out;
5813 }
5814
5815 if (use_btf)
5816 trace__load_vmlinux_btf(&trace);
5817 }
5818
5819 /*
5820 * If we are augmenting syscalls, then combine what we put in the
5821 * __augmented_syscalls__ BPF map with what is in the
5822 * syscalls:sys_exit_FOO tracepoints, i.e. just like we do without BPF,
5823 * combining raw_syscalls:sys_enter with raw_syscalls:sys_exit.
5824 *
5825 * We'll switch to look at two BPF maps, one for sys_enter and the
5826 * other for sys_exit when we start augmenting the sys_exit paths with
5827 * buffers that are being copied from kernel to userspace, think 'read'
5828 * syscall.
5829 */
5830 if (trace.syscalls.events.bpf_output) {
5831 evlist__for_each_entry(trace.evlist, evsel) {
5832 bool raw_syscalls_sys_exit = evsel__name_is(evsel, "raw_syscalls:sys_exit");
5833
5834 if (raw_syscalls_sys_exit) {
5835 trace.raw_augmented_syscalls = true;
5836 goto init_augmented_syscall_tp;
5837 }
5838
5839 if (trace.syscalls.events.bpf_output->priv == NULL &&
5840 strstr(evsel__name(evsel), "syscalls:sys_enter")) {
5841 struct evsel *augmented = trace.syscalls.events.bpf_output;
5842 if (evsel__init_augmented_syscall_tp(augmented, evsel) ||
5843 evsel__init_augmented_syscall_tp_args(augmented))
5844 goto out;
5845 /*
5846 * Augmented is __augmented_syscalls__ BPF_OUTPUT event
5847 * Above we made sure we can get from the payload the tp fields
5848 * that we get from syscalls:sys_enter tracefs format file.
5849 */
5850 augmented->handler = trace__sys_enter;
5851 /*
5852 * Now we do the same for the *syscalls:sys_enter event so that
5853 * if we handle it directly, i.e. if the BPF prog returns 0 so
5854 * as not to filter it, then we'll handle it just like we would
5855 * for the BPF_OUTPUT one:
5856 */
5857 if (evsel__init_augmented_syscall_tp(evsel, evsel) ||
5858 evsel__init_augmented_syscall_tp_args(evsel))
5859 goto out;
5860 evsel->handler = trace__sys_enter;
5861 }
5862
5863 if (strstarts(evsel__name(evsel), "syscalls:sys_exit_")) {
5864 struct syscall_tp *sc;
5865init_augmented_syscall_tp:
5866 if (evsel__init_augmented_syscall_tp(evsel, evsel))
5867 goto out;
5868 sc = __evsel__syscall_tp(evsel);
5869 /*
5870 * For now with BPF raw_augmented we hook into
5871 * raw_syscalls:sys_enter and there we get all
5872 * 6 syscall args plus the tracepoint common
5873 * fields and the syscall_nr (another long).
5874 * So we check if that is the case and if so
5875 * don't look after the sc->args_size but
5876 * always after the full raw_syscalls:sys_enter
5877 * payload, which is fixed.
5878 *
5879 * We'll revisit this later to pass
5880 * s->args_size to the BPF augmenter (now
5881 * tools/perf/examples/bpf/augmented_raw_syscalls.c,
5882 * so that it copies only what we need for each
5883 * syscall, like what happens when we use
5884 * syscalls:sys_enter_NAME, so that we reduce
5885 * the kernel/userspace traffic to just what is
5886 * needed for each syscall.
5887 */
5888 if (trace.raw_augmented_syscalls)
5889 trace.raw_augmented_syscalls_args_size = (6 + 1) * sizeof(long) + sc->id.offset;
5890 evsel__init_augmented_syscall_tp_ret(evsel);
5891 evsel->handler = trace__sys_exit;
5892 }
5893 }
5894 }
5895
5896 if ((argc >= 1) && (strcmp(argv[0], "record") == 0)) {
5897 err = trace__record(&trace, argc-1, &argv[1]);
5898 goto out;
5899 }
5900
5901 /* Using just --errno-summary will trigger --summary */
5902 if (trace.errno_summary && !trace.summary && !trace.summary_only)
5903 trace.summary_only = true;
5904
5905 /* summary_only implies summary option, but don't overwrite summary if set */
5906 if (trace.summary_only)
5907 trace.summary = trace.summary_only;
5908
5909 /* Keep exited threads, otherwise information might be lost for summary */
5910 if (trace.summary) {
5911 symbol_conf.keep_exited_threads = true;
5912 if (trace.summary_mode == SUMMARY__NONE)
5913 trace.summary_mode = SUMMARY__BY_THREAD;
5914
5915 if (!trace.summary_bpf && trace.summary_mode == SUMMARY__BY_CGROUP) {
5916 pr_err("Error: --summary-mode=cgroup only works with --bpf-summary\n");
5917 err = -EINVAL;
5918 goto out;
5919 }
5920 }
5921
5922 if (output_name != NULL) {
5923 err = trace__open_output(&trace, output_name);
5924 if (err < 0) {
5925 perror("failed to create output file");
5926 goto out;
5927 }
5928 }
5929
5930 err = evswitch__init(&trace.evswitch, trace.evlist, stderr);
5931 if (err)
5932 goto out_close;
5933
5934 err = target__validate(&trace.opts.target);
5935 if (err) {
5936 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
5937 fprintf(trace.output, "%s", bf);
5938 goto out_close;
5939 }
5940
5941 if (trace.uid_str) {
5942 uid_t uid = parse_uid(trace.uid_str);
5943
5944 if (uid == UINT_MAX) {
5945 ui__error("Invalid User: %s", trace.uid_str);
5946 err = -EINVAL;
5947 goto out_close;
5948 }
5949 err = parse_uid_filter(trace.evlist, uid);
5950 if (err)
5951 goto out_close;
5952
5953 trace.opts.target.system_wide = true;
5954 }
5955
5956 if (!argc && target__none(&trace.opts.target))
5957 trace.opts.target.system_wide = true;
5958
5959 if (input_name)
5960 err = trace__replay(&trace);
5961 else
5962 err = trace__run(&trace, argc, argv);
5963
5964out_close:
5965 if (output_name != NULL)
5966 fclose(trace.output);
5967out:
5968 trace__exit(&trace);
5969 augmented_syscalls__cleanup();
5970 return err;
5971}