perf trace: Add seccomp beautifier related defines for older systems
[linux-2.6-block.git] / tools / perf / builtin-trace.c
CommitLineData
a598bb5e
ACM
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 <acme@redhat.com>
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 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
4e319027 19#include <traceevent/event-parse.h>
988bdb31 20#include <api/fs/tracing_path.h>
514f1c67 21#include "builtin.h"
752fde44 22#include "util/color.h"
7c304ee0 23#include "util/debug.h"
514f1c67 24#include "util/evlist.h"
4b6ab94e 25#include <subcmd/exec-cmd.h>
752fde44 26#include "util/machine.h"
6810fc91 27#include "util/session.h"
752fde44 28#include "util/thread.h"
4b6ab94e 29#include <subcmd/parse-options.h>
2ae3a312 30#include "util/strlist.h"
bdc89661 31#include "util/intlist.h"
514f1c67 32#include "util/thread_map.h"
bf2575c1 33#include "util/stat.h"
97978b3e 34#include "trace-event.h"
9aca7f17 35#include "util/parse-events.h"
ba504235 36#include "util/bpf-loader.h"
566a0885 37#include "callchain.h"
fd0db102 38#include "syscalltbl.h"
514f1c67 39
fd0db102 40#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
514f1c67 41#include <stdlib.h>
ae685380 42#include <sys/mman.h>
f9da0b0c 43#include <linux/futex.h>
8dd2a131 44#include <linux/err.h>
997bba8c
ACM
45#include <linux/seccomp.h>
46#include <linux/filter.h>
47#include <linux/audit.h>
48#include <sys/ptrace.h>
39878d49 49#include <linux/random.h>
514f1c67 50
456857bd
IM
51/* For older distros: */
52#ifndef MAP_STACK
53# define MAP_STACK 0x20000
54#endif
55
56#ifndef MADV_HWPOISON
57# define MADV_HWPOISON 100
a598bb5e 58
456857bd
IM
59#endif
60
61#ifndef MADV_MERGEABLE
62# define MADV_MERGEABLE 12
63#endif
64
65#ifndef MADV_UNMERGEABLE
66# define MADV_UNMERGEABLE 13
67#endif
68
79d26a6a
BH
69#ifndef EFD_SEMAPHORE
70# define EFD_SEMAPHORE 1
71#endif
72
c188e7ac
ACM
73#ifndef EFD_NONBLOCK
74# define EFD_NONBLOCK 00004000
75#endif
76
77#ifndef EFD_CLOEXEC
78# define EFD_CLOEXEC 02000000
79#endif
80
81#ifndef O_CLOEXEC
82# define O_CLOEXEC 02000000
83#endif
84
85#ifndef SOCK_DCCP
86# define SOCK_DCCP 6
87#endif
88
89#ifndef SOCK_CLOEXEC
90# define SOCK_CLOEXEC 02000000
91#endif
92
93#ifndef SOCK_NONBLOCK
94# define SOCK_NONBLOCK 00004000
95#endif
96
97#ifndef MSG_CMSG_CLOEXEC
98# define MSG_CMSG_CLOEXEC 0x40000000
99#endif
100
a1c2552d
ACM
101#ifndef PERF_FLAG_FD_NO_GROUP
102# define PERF_FLAG_FD_NO_GROUP (1UL << 0)
103#endif
104
105#ifndef PERF_FLAG_FD_OUTPUT
106# define PERF_FLAG_FD_OUTPUT (1UL << 1)
107#endif
108
109#ifndef PERF_FLAG_PID_CGROUP
110# define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */
111#endif
112
113#ifndef PERF_FLAG_FD_CLOEXEC
114# define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */
115#endif
116
d1d438a3
ACM
117struct trace {
118 struct perf_tool tool;
fd0db102 119 struct syscalltbl *sctbl;
d1d438a3
ACM
120 struct {
121 int max;
122 struct syscall *table;
123 struct {
124 struct perf_evsel *sys_enter,
125 *sys_exit;
126 } events;
127 } syscalls;
128 struct record_opts opts;
129 struct perf_evlist *evlist;
130 struct machine *host;
131 struct thread *current;
132 u64 base_time;
133 FILE *output;
134 unsigned long nr_events;
135 struct strlist *ev_qualifier;
136 struct {
137 size_t nr;
138 int *entries;
139 } ev_qualifier_ids;
140 struct intlist *tid_list;
141 struct intlist *pid_list;
142 struct {
143 size_t nr;
144 pid_t *entries;
145 } filter_pids;
146 double duration_filter;
147 double runtime_ms;
148 struct {
149 u64 vfs_getname,
150 proc_getname;
151 } stats;
152 bool not_ev_qualifier;
153 bool live;
154 bool full_time;
155 bool sched;
156 bool multiple_threads;
157 bool summary;
158 bool summary_only;
159 bool show_comm;
160 bool show_tool_stats;
161 bool trace_syscalls;
44621819 162 bool kernel_syscallchains;
d1d438a3
ACM
163 bool force;
164 bool vfs_getname;
165 int trace_pgfaults;
fd0db102 166 int open_id;
d1d438a3 167};
a1c2552d 168
77170988
ACM
169struct tp_field {
170 int offset;
171 union {
172 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
173 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
174 };
175};
176
177#define TP_UINT_FIELD(bits) \
178static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
179{ \
55d43bca
DA
180 u##bits value; \
181 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
182 return value; \
77170988
ACM
183}
184
185TP_UINT_FIELD(8);
186TP_UINT_FIELD(16);
187TP_UINT_FIELD(32);
188TP_UINT_FIELD(64);
189
190#define TP_UINT_FIELD__SWAPPED(bits) \
191static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
192{ \
55d43bca
DA
193 u##bits value; \
194 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
77170988
ACM
195 return bswap_##bits(value);\
196}
197
198TP_UINT_FIELD__SWAPPED(16);
199TP_UINT_FIELD__SWAPPED(32);
200TP_UINT_FIELD__SWAPPED(64);
201
202static int tp_field__init_uint(struct tp_field *field,
203 struct format_field *format_field,
204 bool needs_swap)
205{
206 field->offset = format_field->offset;
207
208 switch (format_field->size) {
209 case 1:
210 field->integer = tp_field__u8;
211 break;
212 case 2:
213 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
214 break;
215 case 4:
216 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
217 break;
218 case 8:
219 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
220 break;
221 default:
222 return -1;
223 }
224
225 return 0;
226}
227
228static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
229{
230 return sample->raw_data + field->offset;
231}
232
233static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
234{
235 field->offset = format_field->offset;
236 field->pointer = tp_field__ptr;
237 return 0;
238}
239
240struct syscall_tp {
241 struct tp_field id;
242 union {
243 struct tp_field args, ret;
244 };
245};
246
247static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
248 struct tp_field *field,
249 const char *name)
250{
251 struct format_field *format_field = perf_evsel__field(evsel, name);
252
253 if (format_field == NULL)
254 return -1;
255
256 return tp_field__init_uint(field, format_field, evsel->needs_swap);
257}
258
259#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
260 ({ struct syscall_tp *sc = evsel->priv;\
261 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
262
263static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
264 struct tp_field *field,
265 const char *name)
266{
267 struct format_field *format_field = perf_evsel__field(evsel, name);
268
269 if (format_field == NULL)
270 return -1;
271
272 return tp_field__init_ptr(field, format_field);
273}
274
275#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
276 ({ struct syscall_tp *sc = evsel->priv;\
277 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
278
279static void perf_evsel__delete_priv(struct perf_evsel *evsel)
280{
04662523 281 zfree(&evsel->priv);
77170988
ACM
282 perf_evsel__delete(evsel);
283}
284
96695d44
NK
285static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
286{
287 evsel->priv = malloc(sizeof(struct syscall_tp));
288 if (evsel->priv != NULL) {
289 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
290 goto out_delete;
291
292 evsel->handler = handler;
293 return 0;
294 }
295
296 return -ENOMEM;
297
298out_delete:
04662523 299 zfree(&evsel->priv);
96695d44
NK
300 return -ENOENT;
301}
302
ef503831 303static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
77170988 304{
ef503831 305 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
77170988 306
9aca7f17 307 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
8dd2a131 308 if (IS_ERR(evsel))
9aca7f17
DA
309 evsel = perf_evsel__newtp("syscalls", direction);
310
8dd2a131
JO
311 if (IS_ERR(evsel))
312 return NULL;
313
314 if (perf_evsel__init_syscall_tp(evsel, handler))
315 goto out_delete;
77170988
ACM
316
317 return evsel;
318
319out_delete:
320 perf_evsel__delete_priv(evsel);
321 return NULL;
322}
323
324#define perf_evsel__sc_tp_uint(evsel, name, sample) \
325 ({ struct syscall_tp *fields = evsel->priv; \
326 fields->name.integer(&fields->name, sample); })
327
328#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
329 ({ struct syscall_tp *fields = evsel->priv; \
330 fields->name.pointer(&fields->name, sample); })
331
01533e97
ACM
332struct syscall_arg {
333 unsigned long val;
75b757ca
ACM
334 struct thread *thread;
335 struct trace *trace;
1f115cb7 336 void *parm;
01533e97
ACM
337 u8 idx;
338 u8 mask;
339};
340
1f115cb7 341struct strarray {
03e3adc9 342 int offset;
1f115cb7
ACM
343 int nr_entries;
344 const char **entries;
345};
346
347#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
348 .nr_entries = ARRAY_SIZE(array), \
349 .entries = array, \
350}
351
03e3adc9
ACM
352#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
353 .offset = off, \
354 .nr_entries = ARRAY_SIZE(array), \
355 .entries = array, \
356}
357
975b7c2f
ACM
358static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
359 const char *intfmt,
360 struct syscall_arg *arg)
1f115cb7 361{
1f115cb7 362 struct strarray *sa = arg->parm;
03e3adc9 363 int idx = arg->val - sa->offset;
1f115cb7
ACM
364
365 if (idx < 0 || idx >= sa->nr_entries)
975b7c2f 366 return scnprintf(bf, size, intfmt, arg->val);
1f115cb7
ACM
367
368 return scnprintf(bf, size, "%s", sa->entries[idx]);
369}
370
975b7c2f
ACM
371static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
372 struct syscall_arg *arg)
373{
374 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
375}
376
1f115cb7
ACM
377#define SCA_STRARRAY syscall_arg__scnprintf_strarray
378
844ae5b4
ACM
379#if defined(__i386__) || defined(__x86_64__)
380/*
381 * FIXME: Make this available to all arches as soon as the ioctl beautifier
382 * gets rewritten to support all arches.
383 */
78645cf3
ACM
384static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
385 struct syscall_arg *arg)
386{
387 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
388}
389
390#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
844ae5b4 391#endif /* defined(__i386__) || defined(__x86_64__) */
78645cf3 392
75b757ca
ACM
393static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
394 struct syscall_arg *arg);
395
396#define SCA_FD syscall_arg__scnprintf_fd
397
398static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
399 struct syscall_arg *arg)
400{
401 int fd = arg->val;
402
403 if (fd == AT_FDCWD)
404 return scnprintf(bf, size, "CWD");
405
406 return syscall_arg__scnprintf_fd(bf, size, arg);
407}
408
409#define SCA_FDAT syscall_arg__scnprintf_fd_at
410
411static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
412 struct syscall_arg *arg);
413
414#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
415
6e7eeb51 416static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
01533e97 417 struct syscall_arg *arg)
13d4ff3e 418{
01533e97 419 return scnprintf(bf, size, "%#lx", arg->val);
13d4ff3e
ACM
420}
421
beccb2b5
ACM
422#define SCA_HEX syscall_arg__scnprintf_hex
423
a1c2552d
ACM
424static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
425 struct syscall_arg *arg)
426{
427 return scnprintf(bf, size, "%d", arg->val);
428}
429
430#define SCA_INT syscall_arg__scnprintf_int
431
6e7eeb51 432static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
01533e97 433 struct syscall_arg *arg)
ae685380 434{
01533e97 435 int printed = 0, prot = arg->val;
ae685380
ACM
436
437 if (prot == PROT_NONE)
438 return scnprintf(bf, size, "NONE");
439#define P_MMAP_PROT(n) \
440 if (prot & PROT_##n) { \
441 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
442 prot &= ~PROT_##n; \
443 }
444
445 P_MMAP_PROT(EXEC);
446 P_MMAP_PROT(READ);
447 P_MMAP_PROT(WRITE);
448#ifdef PROT_SEM
449 P_MMAP_PROT(SEM);
450#endif
451 P_MMAP_PROT(GROWSDOWN);
452 P_MMAP_PROT(GROWSUP);
453#undef P_MMAP_PROT
454
455 if (prot)
456 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
457
458 return printed;
459}
460
461#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
462
6e7eeb51 463static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
01533e97 464 struct syscall_arg *arg)
941557e0 465{
01533e97 466 int printed = 0, flags = arg->val;
941557e0
ACM
467
468#define P_MMAP_FLAG(n) \
469 if (flags & MAP_##n) { \
470 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
471 flags &= ~MAP_##n; \
472 }
473
474 P_MMAP_FLAG(SHARED);
475 P_MMAP_FLAG(PRIVATE);
41817815 476#ifdef MAP_32BIT
941557e0 477 P_MMAP_FLAG(32BIT);
41817815 478#endif
941557e0
ACM
479 P_MMAP_FLAG(ANONYMOUS);
480 P_MMAP_FLAG(DENYWRITE);
481 P_MMAP_FLAG(EXECUTABLE);
482 P_MMAP_FLAG(FILE);
483 P_MMAP_FLAG(FIXED);
484 P_MMAP_FLAG(GROWSDOWN);
f2935f3e 485#ifdef MAP_HUGETLB
941557e0 486 P_MMAP_FLAG(HUGETLB);
f2935f3e 487#endif
941557e0
ACM
488 P_MMAP_FLAG(LOCKED);
489 P_MMAP_FLAG(NONBLOCK);
490 P_MMAP_FLAG(NORESERVE);
491 P_MMAP_FLAG(POPULATE);
492 P_MMAP_FLAG(STACK);
493#ifdef MAP_UNINITIALIZED
494 P_MMAP_FLAG(UNINITIALIZED);
495#endif
496#undef P_MMAP_FLAG
497
498 if (flags)
499 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
500
501 return printed;
502}
503
504#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
505
86998dda
AS
506static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
507 struct syscall_arg *arg)
508{
509 int printed = 0, flags = arg->val;
510
511#define P_MREMAP_FLAG(n) \
512 if (flags & MREMAP_##n) { \
513 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
514 flags &= ~MREMAP_##n; \
515 }
516
517 P_MREMAP_FLAG(MAYMOVE);
518#ifdef MREMAP_FIXED
519 P_MREMAP_FLAG(FIXED);
520#endif
521#undef P_MREMAP_FLAG
522
523 if (flags)
524 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
525
526 return printed;
527}
528
529#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
530
6e7eeb51 531static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
01533e97 532 struct syscall_arg *arg)
9e9716d1 533{
01533e97 534 int behavior = arg->val;
9e9716d1
ACM
535
536 switch (behavior) {
537#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
538 P_MADV_BHV(NORMAL);
539 P_MADV_BHV(RANDOM);
540 P_MADV_BHV(SEQUENTIAL);
541 P_MADV_BHV(WILLNEED);
542 P_MADV_BHV(DONTNEED);
543 P_MADV_BHV(REMOVE);
544 P_MADV_BHV(DONTFORK);
545 P_MADV_BHV(DOFORK);
546 P_MADV_BHV(HWPOISON);
547#ifdef MADV_SOFT_OFFLINE
548 P_MADV_BHV(SOFT_OFFLINE);
549#endif
550 P_MADV_BHV(MERGEABLE);
551 P_MADV_BHV(UNMERGEABLE);
f2935f3e 552#ifdef MADV_HUGEPAGE
9e9716d1 553 P_MADV_BHV(HUGEPAGE);
f2935f3e
DA
554#endif
555#ifdef MADV_NOHUGEPAGE
9e9716d1 556 P_MADV_BHV(NOHUGEPAGE);
f2935f3e 557#endif
9e9716d1
ACM
558#ifdef MADV_DONTDUMP
559 P_MADV_BHV(DONTDUMP);
560#endif
561#ifdef MADV_DODUMP
562 P_MADV_BHV(DODUMP);
563#endif
564#undef P_MADV_PHV
565 default: break;
566 }
567
568 return scnprintf(bf, size, "%#x", behavior);
569}
570
571#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
572
5cea6ff2
ACM
573static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
574 struct syscall_arg *arg)
575{
576 int printed = 0, op = arg->val;
577
578 if (op == 0)
579 return scnprintf(bf, size, "NONE");
580#define P_CMD(cmd) \
581 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
582 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
583 op &= ~LOCK_##cmd; \
584 }
585
586 P_CMD(SH);
587 P_CMD(EX);
588 P_CMD(NB);
589 P_CMD(UN);
590 P_CMD(MAND);
591 P_CMD(RW);
592 P_CMD(READ);
593 P_CMD(WRITE);
594#undef P_OP
595
596 if (op)
597 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
598
599 return printed;
600}
601
602#define SCA_FLOCK syscall_arg__scnprintf_flock
603
01533e97 604static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
f9da0b0c
ACM
605{
606 enum syscall_futex_args {
607 SCF_UADDR = (1 << 0),
608 SCF_OP = (1 << 1),
609 SCF_VAL = (1 << 2),
610 SCF_TIMEOUT = (1 << 3),
611 SCF_UADDR2 = (1 << 4),
612 SCF_VAL3 = (1 << 5),
613 };
01533e97 614 int op = arg->val;
f9da0b0c
ACM
615 int cmd = op & FUTEX_CMD_MASK;
616 size_t printed = 0;
617
618 switch (cmd) {
619#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
01533e97
ACM
620 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
621 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
622 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
623 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
624 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
625 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
f9da0b0c 626 P_FUTEX_OP(WAKE_OP); break;
01533e97
ACM
627 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
628 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
629 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
630 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
631 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
f9da0b0c
ACM
632 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
633 default: printed = scnprintf(bf, size, "%#x", cmd); break;
634 }
635
636 if (op & FUTEX_PRIVATE_FLAG)
637 printed += scnprintf(bf + printed, size - printed, "|PRIV");
638
639 if (op & FUTEX_CLOCK_REALTIME)
640 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
641
642 return printed;
643}
644
efe6b882
ACM
645#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
646
729a7841
ACM
647static const char *bpf_cmd[] = {
648 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
649 "MAP_GET_NEXT_KEY", "PROG_LOAD",
650};
651static DEFINE_STRARRAY(bpf_cmd);
652
03e3adc9
ACM
653static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
654static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
eac032c5 655
1f115cb7
ACM
656static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
657static DEFINE_STRARRAY(itimers);
658
b62bee1b
ACM
659static const char *keyctl_options[] = {
660 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
661 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
662 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
663 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
664 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
665};
666static DEFINE_STRARRAY(keyctl_options);
667
efe6b882
ACM
668static const char *whences[] = { "SET", "CUR", "END",
669#ifdef SEEK_DATA
670"DATA",
671#endif
672#ifdef SEEK_HOLE
673"HOLE",
674#endif
675};
676static DEFINE_STRARRAY(whences);
f9da0b0c 677
80f587d5
ACM
678static const char *fcntl_cmds[] = {
679 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
680 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
681 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
682 "F_GETOWNER_UIDS",
683};
684static DEFINE_STRARRAY(fcntl_cmds);
685
c045bf02
ACM
686static const char *rlimit_resources[] = {
687 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
688 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
689 "RTTIME",
690};
691static DEFINE_STRARRAY(rlimit_resources);
692
eb5b1b14
ACM
693static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
694static DEFINE_STRARRAY(sighow);
695
4f8c1b74
DA
696static const char *clockid[] = {
697 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
28ebb87c
ACM
698 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
699 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
4f8c1b74
DA
700};
701static DEFINE_STRARRAY(clockid);
702
e10bce81
ACM
703static const char *socket_families[] = {
704 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
705 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
706 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
707 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
708 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
709 "ALG", "NFC", "VSOCK",
710};
711static DEFINE_STRARRAY(socket_families);
712
a28b24b2
ACM
713#ifndef SOCK_TYPE_MASK
714#define SOCK_TYPE_MASK 0xf
715#endif
716
717static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
718 struct syscall_arg *arg)
719{
720 size_t printed;
721 int type = arg->val,
722 flags = type & ~SOCK_TYPE_MASK;
723
724 type &= SOCK_TYPE_MASK;
725 /*
726 * Can't use a strarray, MIPS may override for ABI reasons.
727 */
728 switch (type) {
729#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
730 P_SK_TYPE(STREAM);
731 P_SK_TYPE(DGRAM);
732 P_SK_TYPE(RAW);
733 P_SK_TYPE(RDM);
734 P_SK_TYPE(SEQPACKET);
735 P_SK_TYPE(DCCP);
736 P_SK_TYPE(PACKET);
737#undef P_SK_TYPE
738 default:
739 printed = scnprintf(bf, size, "%#x", type);
740 }
741
742#define P_SK_FLAG(n) \
743 if (flags & SOCK_##n) { \
744 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
745 flags &= ~SOCK_##n; \
746 }
747
748 P_SK_FLAG(CLOEXEC);
749 P_SK_FLAG(NONBLOCK);
750#undef P_SK_FLAG
751
752 if (flags)
753 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
754
755 return printed;
756}
757
758#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
759
b2cc99fd
ACM
760#ifndef MSG_PROBE
761#define MSG_PROBE 0x10
762#endif
b6e8f8f4
DA
763#ifndef MSG_WAITFORONE
764#define MSG_WAITFORONE 0x10000
765#endif
b2cc99fd
ACM
766#ifndef MSG_SENDPAGE_NOTLAST
767#define MSG_SENDPAGE_NOTLAST 0x20000
768#endif
769#ifndef MSG_FASTOPEN
770#define MSG_FASTOPEN 0x20000000
771#endif
772
773static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
774 struct syscall_arg *arg)
775{
776 int printed = 0, flags = arg->val;
777
778 if (flags == 0)
779 return scnprintf(bf, size, "NONE");
780#define P_MSG_FLAG(n) \
781 if (flags & MSG_##n) { \
782 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
783 flags &= ~MSG_##n; \
784 }
785
786 P_MSG_FLAG(OOB);
787 P_MSG_FLAG(PEEK);
788 P_MSG_FLAG(DONTROUTE);
789 P_MSG_FLAG(TRYHARD);
790 P_MSG_FLAG(CTRUNC);
791 P_MSG_FLAG(PROBE);
792 P_MSG_FLAG(TRUNC);
793 P_MSG_FLAG(DONTWAIT);
794 P_MSG_FLAG(EOR);
795 P_MSG_FLAG(WAITALL);
796 P_MSG_FLAG(FIN);
797 P_MSG_FLAG(SYN);
798 P_MSG_FLAG(CONFIRM);
799 P_MSG_FLAG(RST);
800 P_MSG_FLAG(ERRQUEUE);
801 P_MSG_FLAG(NOSIGNAL);
802 P_MSG_FLAG(MORE);
803 P_MSG_FLAG(WAITFORONE);
804 P_MSG_FLAG(SENDPAGE_NOTLAST);
805 P_MSG_FLAG(FASTOPEN);
806 P_MSG_FLAG(CMSG_CLOEXEC);
807#undef P_MSG_FLAG
808
809 if (flags)
810 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
811
812 return printed;
813}
814
815#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
816
51108999
ACM
817static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
818 struct syscall_arg *arg)
819{
820 size_t printed = 0;
821 int mode = arg->val;
822
823 if (mode == F_OK) /* 0 */
824 return scnprintf(bf, size, "F");
825#define P_MODE(n) \
826 if (mode & n##_OK) { \
827 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
828 mode &= ~n##_OK; \
829 }
830
831 P_MODE(R);
832 P_MODE(W);
833 P_MODE(X);
834#undef P_MODE
835
836 if (mode)
837 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
838
839 return printed;
840}
841
842#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
843
f994592d
ACM
844static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
845 struct syscall_arg *arg);
846
847#define SCA_FILENAME syscall_arg__scnprintf_filename
848
be65a89a 849static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
01533e97 850 struct syscall_arg *arg)
be65a89a 851{
01533e97 852 int printed = 0, flags = arg->val;
be65a89a
ACM
853
854 if (!(flags & O_CREAT))
01533e97 855 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
be65a89a
ACM
856
857 if (flags == 0)
858 return scnprintf(bf, size, "RDONLY");
859#define P_FLAG(n) \
860 if (flags & O_##n) { \
861 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
862 flags &= ~O_##n; \
863 }
864
865 P_FLAG(APPEND);
866 P_FLAG(ASYNC);
867 P_FLAG(CLOEXEC);
868 P_FLAG(CREAT);
869 P_FLAG(DIRECT);
870 P_FLAG(DIRECTORY);
871 P_FLAG(EXCL);
872 P_FLAG(LARGEFILE);
873 P_FLAG(NOATIME);
874 P_FLAG(NOCTTY);
875#ifdef O_NONBLOCK
876 P_FLAG(NONBLOCK);
877#elif O_NDELAY
878 P_FLAG(NDELAY);
879#endif
880#ifdef O_PATH
881 P_FLAG(PATH);
882#endif
883 P_FLAG(RDWR);
884#ifdef O_DSYNC
885 if ((flags & O_SYNC) == O_SYNC)
886 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
887 else {
888 P_FLAG(DSYNC);
889 }
890#else
891 P_FLAG(SYNC);
892#endif
893 P_FLAG(TRUNC);
894 P_FLAG(WRONLY);
895#undef P_FLAG
896
897 if (flags)
898 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
899
900 return printed;
901}
902
903#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
904
a1c2552d
ACM
905static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size,
906 struct syscall_arg *arg)
907{
908 int printed = 0, flags = arg->val;
909
910 if (flags == 0)
911 return 0;
912
913#define P_FLAG(n) \
914 if (flags & PERF_FLAG_##n) { \
915 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
916 flags &= ~PERF_FLAG_##n; \
917 }
918
919 P_FLAG(FD_NO_GROUP);
920 P_FLAG(FD_OUTPUT);
921 P_FLAG(PID_CGROUP);
922 P_FLAG(FD_CLOEXEC);
923#undef P_FLAG
924
925 if (flags)
926 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
927
928 return printed;
929}
930
931#define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags
932
49af9e93
ACM
933static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
934 struct syscall_arg *arg)
935{
936 int printed = 0, flags = arg->val;
937
938 if (flags == 0)
939 return scnprintf(bf, size, "NONE");
940#define P_FLAG(n) \
941 if (flags & EFD_##n) { \
942 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
943 flags &= ~EFD_##n; \
944 }
945
946 P_FLAG(SEMAPHORE);
947 P_FLAG(CLOEXEC);
948 P_FLAG(NONBLOCK);
949#undef P_FLAG
950
951 if (flags)
952 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
953
954 return printed;
955}
956
957#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
958
46cce19b
ACM
959static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
960 struct syscall_arg *arg)
961{
962 int printed = 0, flags = arg->val;
963
964#define P_FLAG(n) \
965 if (flags & O_##n) { \
966 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
967 flags &= ~O_##n; \
968 }
969
970 P_FLAG(CLOEXEC);
971 P_FLAG(NONBLOCK);
972#undef P_FLAG
973
974 if (flags)
975 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
976
977 return printed;
978}
979
980#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
981
8bad5b0a
ACM
982static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
983{
984 int sig = arg->val;
985
986 switch (sig) {
987#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
988 P_SIGNUM(HUP);
989 P_SIGNUM(INT);
990 P_SIGNUM(QUIT);
991 P_SIGNUM(ILL);
992 P_SIGNUM(TRAP);
993 P_SIGNUM(ABRT);
994 P_SIGNUM(BUS);
995 P_SIGNUM(FPE);
996 P_SIGNUM(KILL);
997 P_SIGNUM(USR1);
998 P_SIGNUM(SEGV);
999 P_SIGNUM(USR2);
1000 P_SIGNUM(PIPE);
1001 P_SIGNUM(ALRM);
1002 P_SIGNUM(TERM);
8bad5b0a
ACM
1003 P_SIGNUM(CHLD);
1004 P_SIGNUM(CONT);
1005 P_SIGNUM(STOP);
1006 P_SIGNUM(TSTP);
1007 P_SIGNUM(TTIN);
1008 P_SIGNUM(TTOU);
1009 P_SIGNUM(URG);
1010 P_SIGNUM(XCPU);
1011 P_SIGNUM(XFSZ);
1012 P_SIGNUM(VTALRM);
1013 P_SIGNUM(PROF);
1014 P_SIGNUM(WINCH);
1015 P_SIGNUM(IO);
1016 P_SIGNUM(PWR);
1017 P_SIGNUM(SYS);
02c5bb4a
BH
1018#ifdef SIGEMT
1019 P_SIGNUM(EMT);
1020#endif
1021#ifdef SIGSTKFLT
1022 P_SIGNUM(STKFLT);
1023#endif
1024#ifdef SIGSWI
1025 P_SIGNUM(SWI);
1026#endif
8bad5b0a
ACM
1027 default: break;
1028 }
1029
1030 return scnprintf(bf, size, "%#x", sig);
1031}
1032
1033#define SCA_SIGNUM syscall_arg__scnprintf_signum
1034
844ae5b4
ACM
1035#if defined(__i386__) || defined(__x86_64__)
1036/*
1037 * FIXME: Make this available to all arches.
1038 */
78645cf3
ACM
1039#define TCGETS 0x5401
1040
1041static const char *tioctls[] = {
1042 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
1043 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
1044 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
1045 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
1046 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
1047 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
1048 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
1049 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
1050 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
1051 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
1052 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
1053 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
1054 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
1055 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
1056 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
1057};
1058
1059static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
844ae5b4 1060#endif /* defined(__i386__) || defined(__x86_64__) */
78645cf3 1061
6fb35b95
ACM
1062#ifndef SECCOMP_SET_MODE_STRICT
1063#define SECCOMP_SET_MODE_STRICT 0
1064#endif
1065#ifndef SECCOMP_SET_MODE_FILTER
1066#define SECCOMP_SET_MODE_FILTER 1
1067#endif
1068
997bba8c
ACM
1069static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg)
1070{
1071 int op = arg->val;
1072 size_t printed = 0;
1073
1074 switch (op) {
1075#define P_SECCOMP_SET_MODE_OP(n) case SECCOMP_SET_MODE_##n: printed = scnprintf(bf, size, #n); break
1076 P_SECCOMP_SET_MODE_OP(STRICT);
1077 P_SECCOMP_SET_MODE_OP(FILTER);
1078#undef P_SECCOMP_SET_MODE_OP
1079 default: printed = scnprintf(bf, size, "%#x", op); break;
1080 }
1081
1082 return printed;
1083}
1084
1085#define SCA_SECCOMP_OP syscall_arg__scnprintf_seccomp_op
1086
6fb35b95
ACM
1087#ifndef SECCOMP_FILTER_FLAG_TSYNC
1088#define SECCOMP_FILTER_FLAG_TSYNC 1
1089#endif
1090
997bba8c
ACM
1091static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size,
1092 struct syscall_arg *arg)
1093{
1094 int printed = 0, flags = arg->val;
1095
1096#define P_FLAG(n) \
1097 if (flags & SECCOMP_FILTER_FLAG_##n) { \
1098 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
1099 flags &= ~SECCOMP_FILTER_FLAG_##n; \
1100 }
1101
1102 P_FLAG(TSYNC);
1103#undef P_FLAG
1104
1105 if (flags)
1106 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
1107
1108 return printed;
1109}
1110
1111#define SCA_SECCOMP_FLAGS syscall_arg__scnprintf_seccomp_flags
1112
39878d49
ACM
1113static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
1114 struct syscall_arg *arg)
1115{
1116 int printed = 0, flags = arg->val;
1117
1118#define P_FLAG(n) \
1119 if (flags & GRND_##n) { \
1120 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
1121 flags &= ~GRND_##n; \
1122 }
1123
1124 P_FLAG(RANDOM);
1125 P_FLAG(NONBLOCK);
1126#undef P_FLAG
1127
1128 if (flags)
1129 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
1130
1131 return printed;
1132}
1133
1134#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
1135
453350dd
ACM
1136#define STRARRAY(arg, name, array) \
1137 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
1138 .arg_parm = { [arg] = &strarray__##array, }
1139
d1d438a3 1140#include "trace/beauty/pid.c"
ba2f22cf 1141#include "trace/beauty/mode_t.c"
a3bca91f 1142#include "trace/beauty/sched_policy.c"
7206b900 1143#include "trace/beauty/waitid_options.c"
a3bca91f 1144
514f1c67
ACM
1145static struct syscall_fmt {
1146 const char *name;
aec1930b 1147 const char *alias;
01533e97 1148 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
1f115cb7 1149 void *arg_parm[6];
514f1c67 1150 bool errmsg;
11c8e39f 1151 bool errpid;
514f1c67 1152 bool timeout;
04b34729 1153 bool hexret;
514f1c67 1154} syscall_fmts[] = {
51108999 1155 { .name = "access", .errmsg = true,
34221118
ACM
1156 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1157 [1] = SCA_ACCMODE, /* mode */ }, },
aec1930b 1158 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
729a7841 1159 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
beccb2b5
ACM
1160 { .name = "brk", .hexret = true,
1161 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
34221118
ACM
1162 { .name = "chdir", .errmsg = true,
1163 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1164 { .name = "chmod", .errmsg = true,
1165 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1166 { .name = "chroot", .errmsg = true,
1167 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
4f8c1b74 1168 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
11c8e39f 1169 { .name = "clone", .errpid = true, },
75b757ca 1170 { .name = "close", .errmsg = true,
48000a1a 1171 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
a14bb860 1172 { .name = "connect", .errmsg = true, },
34221118
ACM
1173 { .name = "creat", .errmsg = true,
1174 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
75b757ca 1175 { .name = "dup", .errmsg = true,
48000a1a 1176 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1177 { .name = "dup2", .errmsg = true,
48000a1a 1178 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1179 { .name = "dup3", .errmsg = true,
48000a1a 1180 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
453350dd 1181 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
49af9e93
ACM
1182 { .name = "eventfd2", .errmsg = true,
1183 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
75b757ca 1184 { .name = "faccessat", .errmsg = true,
34221118
ACM
1185 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1186 [1] = SCA_FILENAME, /* filename */ }, },
75b757ca 1187 { .name = "fadvise64", .errmsg = true,
48000a1a 1188 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1189 { .name = "fallocate", .errmsg = true,
48000a1a 1190 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1191 { .name = "fchdir", .errmsg = true,
48000a1a 1192 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1193 { .name = "fchmod", .errmsg = true,
48000a1a 1194 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1195 { .name = "fchmodat", .errmsg = true,
090389b6
ACM
1196 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1197 [1] = SCA_FILENAME, /* filename */ }, },
75b757ca 1198 { .name = "fchown", .errmsg = true,
48000a1a 1199 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1200 { .name = "fchownat", .errmsg = true,
34221118
ACM
1201 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1202 [1] = SCA_FILENAME, /* filename */ }, },
75b757ca
ACM
1203 { .name = "fcntl", .errmsg = true,
1204 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1205 [1] = SCA_STRARRAY, /* cmd */ },
1206 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1207 { .name = "fdatasync", .errmsg = true,
48000a1a 1208 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
5cea6ff2 1209 { .name = "flock", .errmsg = true,
75b757ca
ACM
1210 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1211 [1] = SCA_FLOCK, /* cmd */ }, },
1212 { .name = "fsetxattr", .errmsg = true,
48000a1a 1213 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1214 { .name = "fstat", .errmsg = true, .alias = "newfstat",
48000a1a 1215 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1216 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
34221118
ACM
1217 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1218 [1] = SCA_FILENAME, /* filename */ }, },
75b757ca 1219 { .name = "fstatfs", .errmsg = true,
48000a1a 1220 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1221 { .name = "fsync", .errmsg = true,
48000a1a 1222 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1223 { .name = "ftruncate", .errmsg = true,
48000a1a 1224 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
f9da0b0c
ACM
1225 { .name = "futex", .errmsg = true,
1226 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
75b757ca 1227 { .name = "futimesat", .errmsg = true,
090389b6
ACM
1228 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1229 [1] = SCA_FILENAME, /* filename */ }, },
75b757ca 1230 { .name = "getdents", .errmsg = true,
48000a1a 1231 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1232 { .name = "getdents64", .errmsg = true,
48000a1a 1233 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
453350dd 1234 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
c65f1070 1235 { .name = "getpid", .errpid = true, },
d1d438a3 1236 { .name = "getpgid", .errpid = true, },
c65f1070 1237 { .name = "getppid", .errpid = true, },
39878d49
ACM
1238 { .name = "getrandom", .errmsg = true,
1239 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
453350dd 1240 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
34221118
ACM
1241 { .name = "getxattr", .errmsg = true,
1242 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1243 { .name = "inotify_add_watch", .errmsg = true,
1244 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
beccb2b5 1245 { .name = "ioctl", .errmsg = true,
48000a1a 1246 .arg_scnprintf = { [0] = SCA_FD, /* fd */
844ae5b4
ACM
1247#if defined(__i386__) || defined(__x86_64__)
1248/*
1249 * FIXME: Make this available to all arches.
1250 */
78645cf3
ACM
1251 [1] = SCA_STRHEXARRAY, /* cmd */
1252 [2] = SCA_HEX, /* arg */ },
1253 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
844ae5b4
ACM
1254#else
1255 [2] = SCA_HEX, /* arg */ }, },
1256#endif
b62bee1b 1257 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
8bad5b0a
ACM
1258 { .name = "kill", .errmsg = true,
1259 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
34221118
ACM
1260 { .name = "lchown", .errmsg = true,
1261 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1262 { .name = "lgetxattr", .errmsg = true,
1263 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
75b757ca 1264 { .name = "linkat", .errmsg = true,
48000a1a 1265 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
34221118
ACM
1266 { .name = "listxattr", .errmsg = true,
1267 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
090389b6
ACM
1268 { .name = "llistxattr", .errmsg = true,
1269 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1270 { .name = "lremovexattr", .errmsg = true,
1271 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
75b757ca
ACM
1272 { .name = "lseek", .errmsg = true,
1273 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1274 [2] = SCA_STRARRAY, /* whence */ },
1275 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
34221118
ACM
1276 { .name = "lsetxattr", .errmsg = true,
1277 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
090389b6
ACM
1278 { .name = "lstat", .errmsg = true, .alias = "newlstat",
1279 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
34221118
ACM
1280 { .name = "lsxattr", .errmsg = true,
1281 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
9e9716d1
ACM
1282 { .name = "madvise", .errmsg = true,
1283 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1284 [2] = SCA_MADV_BHV, /* behavior */ }, },
34221118
ACM
1285 { .name = "mkdir", .errmsg = true,
1286 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
75b757ca 1287 { .name = "mkdirat", .errmsg = true,
34221118
ACM
1288 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1289 [1] = SCA_FILENAME, /* pathname */ }, },
1290 { .name = "mknod", .errmsg = true,
1291 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
75b757ca 1292 { .name = "mknodat", .errmsg = true,
090389b6
ACM
1293 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1294 [1] = SCA_FILENAME, /* filename */ }, },
3d903aa7
ACM
1295 { .name = "mlock", .errmsg = true,
1296 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1297 { .name = "mlockall", .errmsg = true,
1298 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
beccb2b5 1299 { .name = "mmap", .hexret = true,
ae685380 1300 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
941557e0 1301 [2] = SCA_MMAP_PROT, /* prot */
73faab3a
NK
1302 [3] = SCA_MMAP_FLAGS, /* flags */
1303 [4] = SCA_FD, /* fd */ }, },
beccb2b5 1304 { .name = "mprotect", .errmsg = true,
ae685380
ACM
1305 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1306 [2] = SCA_MMAP_PROT, /* prot */ }, },
090389b6
ACM
1307 { .name = "mq_unlink", .errmsg = true,
1308 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
ae685380
ACM
1309 { .name = "mremap", .hexret = true,
1310 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
86998dda 1311 [3] = SCA_MREMAP_FLAGS, /* flags */
ae685380 1312 [4] = SCA_HEX, /* new_addr */ }, },
3d903aa7
ACM
1313 { .name = "munlock", .errmsg = true,
1314 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
beccb2b5
ACM
1315 { .name = "munmap", .errmsg = true,
1316 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
75b757ca 1317 { .name = "name_to_handle_at", .errmsg = true,
48000a1a 1318 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
75b757ca 1319 { .name = "newfstatat", .errmsg = true,
34221118
ACM
1320 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1321 [1] = SCA_FILENAME, /* filename */ }, },
be65a89a 1322 { .name = "open", .errmsg = true,
f994592d
ACM
1323 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1324 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
31cd3855 1325 { .name = "open_by_handle_at", .errmsg = true,
75b757ca
ACM
1326 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1327 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
31cd3855 1328 { .name = "openat", .errmsg = true,
75b757ca 1329 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
34221118 1330 [1] = SCA_FILENAME, /* filename */
75b757ca 1331 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
a1c2552d
ACM
1332 { .name = "perf_event_open", .errmsg = true,
1333 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1334 [2] = SCA_INT, /* cpu */
1335 [3] = SCA_FD, /* group_fd */
1336 [4] = SCA_PERF_FLAGS, /* flags */ }, },
46cce19b
ACM
1337 { .name = "pipe2", .errmsg = true,
1338 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
aec1930b
ACM
1339 { .name = "poll", .errmsg = true, .timeout = true, },
1340 { .name = "ppoll", .errmsg = true, .timeout = true, },
75b757ca 1341 { .name = "pread", .errmsg = true, .alias = "pread64",
48000a1a 1342 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1343 { .name = "preadv", .errmsg = true, .alias = "pread",
48000a1a 1344 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
453350dd 1345 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
75b757ca 1346 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
48000a1a 1347 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1348 { .name = "pwritev", .errmsg = true,
48000a1a 1349 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1350 { .name = "read", .errmsg = true,
48000a1a 1351 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
34221118
ACM
1352 { .name = "readlink", .errmsg = true,
1353 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
75b757ca 1354 { .name = "readlinkat", .errmsg = true,
34221118
ACM
1355 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1356 [1] = SCA_FILENAME, /* pathname */ }, },
75b757ca 1357 { .name = "readv", .errmsg = true,
48000a1a 1358 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
b2cc99fd 1359 { .name = "recvfrom", .errmsg = true,
8d8c66a2
ACM
1360 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1361 [3] = SCA_MSG_FLAGS, /* flags */ }, },
b2cc99fd 1362 { .name = "recvmmsg", .errmsg = true,
8d8c66a2
ACM
1363 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1364 [3] = SCA_MSG_FLAGS, /* flags */ }, },
b2cc99fd 1365 { .name = "recvmsg", .errmsg = true,
8d8c66a2
ACM
1366 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1367 [2] = SCA_MSG_FLAGS, /* flags */ }, },
34221118
ACM
1368 { .name = "removexattr", .errmsg = true,
1369 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
75b757ca 1370 { .name = "renameat", .errmsg = true,
48000a1a 1371 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
34221118
ACM
1372 { .name = "rmdir", .errmsg = true,
1373 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
8bad5b0a
ACM
1374 { .name = "rt_sigaction", .errmsg = true,
1375 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
453350dd 1376 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
8bad5b0a
ACM
1377 { .name = "rt_sigqueueinfo", .errmsg = true,
1378 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1379 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1380 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
a3bca91f
ACM
1381 { .name = "sched_setscheduler", .errmsg = true,
1382 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
997bba8c
ACM
1383 { .name = "seccomp", .errmsg = true,
1384 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
1385 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
aec1930b 1386 { .name = "select", .errmsg = true, .timeout = true, },
b2cc99fd 1387 { .name = "sendmmsg", .errmsg = true,
8d8c66a2
ACM
1388 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1389 [3] = SCA_MSG_FLAGS, /* flags */ }, },
b2cc99fd 1390 { .name = "sendmsg", .errmsg = true,
8d8c66a2
ACM
1391 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1392 [2] = SCA_MSG_FLAGS, /* flags */ }, },
b2cc99fd 1393 { .name = "sendto", .errmsg = true,
8d8c66a2
ACM
1394 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1395 [3] = SCA_MSG_FLAGS, /* flags */ }, },
c65f1070 1396 { .name = "set_tid_address", .errpid = true, },
453350dd 1397 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
d1d438a3 1398 { .name = "setpgid", .errmsg = true, },
453350dd 1399 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
34221118
ACM
1400 { .name = "setxattr", .errmsg = true,
1401 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
75b757ca 1402 { .name = "shutdown", .errmsg = true,
48000a1a 1403 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
e10bce81 1404 { .name = "socket", .errmsg = true,
a28b24b2
ACM
1405 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1406 [1] = SCA_SK_TYPE, /* type */ },
07120aa5
ACM
1407 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
1408 { .name = "socketpair", .errmsg = true,
1409 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1410 [1] = SCA_SK_TYPE, /* type */ },
e10bce81 1411 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
090389b6
ACM
1412 { .name = "stat", .errmsg = true, .alias = "newstat",
1413 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
34221118
ACM
1414 { .name = "statfs", .errmsg = true,
1415 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1416 { .name = "swapoff", .errmsg = true,
1417 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1418 { .name = "swapon", .errmsg = true,
1419 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
75b757ca 1420 { .name = "symlinkat", .errmsg = true,
48000a1a 1421 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
8bad5b0a
ACM
1422 { .name = "tgkill", .errmsg = true,
1423 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1424 { .name = "tkill", .errmsg = true,
1425 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
34221118
ACM
1426 { .name = "truncate", .errmsg = true,
1427 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
e5959683 1428 { .name = "uname", .errmsg = true, .alias = "newuname", },
75b757ca 1429 { .name = "unlinkat", .errmsg = true,
34221118
ACM
1430 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1431 [1] = SCA_FILENAME, /* pathname */ }, },
1432 { .name = "utime", .errmsg = true,
1433 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
75b757ca 1434 { .name = "utimensat", .errmsg = true,
34221118
ACM
1435 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1436 [1] = SCA_FILENAME, /* filename */ }, },
1437 { .name = "utimes", .errmsg = true,
1438 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
090389b6
ACM
1439 { .name = "vmsplice", .errmsg = true,
1440 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
11c8e39f 1441 { .name = "wait4", .errpid = true,
7206b900 1442 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
11c8e39f 1443 { .name = "waitid", .errpid = true,
7206b900 1444 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
75b757ca 1445 { .name = "write", .errmsg = true,
48000a1a 1446 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1447 { .name = "writev", .errmsg = true,
48000a1a 1448 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
514f1c67
ACM
1449};
1450
1451static int syscall_fmt__cmp(const void *name, const void *fmtp)
1452{
1453 const struct syscall_fmt *fmt = fmtp;
1454 return strcmp(name, fmt->name);
1455}
1456
1457static struct syscall_fmt *syscall_fmt__find(const char *name)
1458{
1459 const int nmemb = ARRAY_SIZE(syscall_fmts);
1460 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1461}
1462
1463struct syscall {
1464 struct event_format *tp_format;
f208bd8d
ACM
1465 int nr_args;
1466 struct format_field *args;
514f1c67 1467 const char *name;
5089f20e 1468 bool is_exit;
514f1c67 1469 struct syscall_fmt *fmt;
01533e97 1470 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
1f115cb7 1471 void **arg_parm;
514f1c67
ACM
1472};
1473
60c907ab
ACM
1474static size_t fprintf_duration(unsigned long t, FILE *fp)
1475{
1476 double duration = (double)t / NSEC_PER_MSEC;
1477 size_t printed = fprintf(fp, "(");
1478
1479 if (duration >= 1.0)
1480 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1481 else if (duration >= 0.01)
1482 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1483 else
1484 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
c24ff998 1485 return printed + fprintf(fp, "): ");
60c907ab
ACM
1486}
1487
f994592d
ACM
1488/**
1489 * filename.ptr: The filename char pointer that will be vfs_getname'd
1490 * filename.entry_str_pos: Where to insert the string translated from
1491 * filename.ptr by the vfs_getname tracepoint/kprobe.
1492 */
752fde44
ACM
1493struct thread_trace {
1494 u64 entry_time;
1495 u64 exit_time;
1496 bool entry_pending;
efd5745e 1497 unsigned long nr_events;
a2ea67d7 1498 unsigned long pfmaj, pfmin;
752fde44 1499 char *entry_str;
1302d88e 1500 double runtime_ms;
f994592d
ACM
1501 struct {
1502 unsigned long ptr;
7f4f8001
ACM
1503 short int entry_str_pos;
1504 bool pending_open;
1505 unsigned int namelen;
1506 char *name;
f994592d 1507 } filename;
75b757ca
ACM
1508 struct {
1509 int max;
1510 char **table;
1511 } paths;
bf2575c1
DA
1512
1513 struct intlist *syscall_stats;
752fde44
ACM
1514};
1515
1516static struct thread_trace *thread_trace__new(void)
1517{
75b757ca
ACM
1518 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1519
1520 if (ttrace)
1521 ttrace->paths.max = -1;
1522
bf2575c1
DA
1523 ttrace->syscall_stats = intlist__new(NULL);
1524
75b757ca 1525 return ttrace;
752fde44
ACM
1526}
1527
c24ff998 1528static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
752fde44 1529{
efd5745e
ACM
1530 struct thread_trace *ttrace;
1531
752fde44
ACM
1532 if (thread == NULL)
1533 goto fail;
1534
89dceb22
NK
1535 if (thread__priv(thread) == NULL)
1536 thread__set_priv(thread, thread_trace__new());
48000a1a 1537
89dceb22 1538 if (thread__priv(thread) == NULL)
752fde44
ACM
1539 goto fail;
1540
89dceb22 1541 ttrace = thread__priv(thread);
efd5745e
ACM
1542 ++ttrace->nr_events;
1543
1544 return ttrace;
752fde44 1545fail:
c24ff998 1546 color_fprintf(fp, PERF_COLOR_RED,
752fde44
ACM
1547 "WARNING: not enough memory, dropping samples!\n");
1548 return NULL;
1549}
1550
598d02c5
SF
1551#define TRACE_PFMAJ (1 << 0)
1552#define TRACE_PFMIN (1 << 1)
1553
e4d44e83
ACM
1554static const size_t trace__entry_str_size = 2048;
1555
97119f37 1556static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
75b757ca 1557{
89dceb22 1558 struct thread_trace *ttrace = thread__priv(thread);
75b757ca
ACM
1559
1560 if (fd > ttrace->paths.max) {
1561 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1562
1563 if (npath == NULL)
1564 return -1;
1565
1566 if (ttrace->paths.max != -1) {
1567 memset(npath + ttrace->paths.max + 1, 0,
1568 (fd - ttrace->paths.max) * sizeof(char *));
1569 } else {
1570 memset(npath, 0, (fd + 1) * sizeof(char *));
1571 }
1572
1573 ttrace->paths.table = npath;
1574 ttrace->paths.max = fd;
1575 }
1576
1577 ttrace->paths.table[fd] = strdup(pathname);
1578
1579 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1580}
1581
97119f37
ACM
1582static int thread__read_fd_path(struct thread *thread, int fd)
1583{
1584 char linkname[PATH_MAX], pathname[PATH_MAX];
1585 struct stat st;
1586 int ret;
1587
1588 if (thread->pid_ == thread->tid) {
1589 scnprintf(linkname, sizeof(linkname),
1590 "/proc/%d/fd/%d", thread->pid_, fd);
1591 } else {
1592 scnprintf(linkname, sizeof(linkname),
1593 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1594 }
1595
1596 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1597 return -1;
1598
1599 ret = readlink(linkname, pathname, sizeof(pathname));
1600
1601 if (ret < 0 || ret > st.st_size)
1602 return -1;
1603
1604 pathname[ret] = '\0';
1605 return trace__set_fd_pathname(thread, fd, pathname);
1606}
1607
c522739d
ACM
1608static const char *thread__fd_path(struct thread *thread, int fd,
1609 struct trace *trace)
75b757ca 1610{
89dceb22 1611 struct thread_trace *ttrace = thread__priv(thread);
75b757ca
ACM
1612
1613 if (ttrace == NULL)
1614 return NULL;
1615
1616 if (fd < 0)
1617 return NULL;
1618
cdcd1e6b 1619 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
c522739d
ACM
1620 if (!trace->live)
1621 return NULL;
1622 ++trace->stats.proc_getname;
cdcd1e6b 1623 if (thread__read_fd_path(thread, fd))
c522739d
ACM
1624 return NULL;
1625 }
75b757ca
ACM
1626
1627 return ttrace->paths.table[fd];
1628}
1629
1630static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1631 struct syscall_arg *arg)
1632{
1633 int fd = arg->val;
1634 size_t printed = scnprintf(bf, size, "%d", fd);
c522739d 1635 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
75b757ca
ACM
1636
1637 if (path)
1638 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1639
1640 return printed;
1641}
1642
1643static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1644 struct syscall_arg *arg)
1645{
1646 int fd = arg->val;
1647 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
89dceb22 1648 struct thread_trace *ttrace = thread__priv(arg->thread);
75b757ca 1649
04662523
ACM
1650 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1651 zfree(&ttrace->paths.table[fd]);
75b757ca
ACM
1652
1653 return printed;
1654}
1655
f994592d
ACM
1656static void thread__set_filename_pos(struct thread *thread, const char *bf,
1657 unsigned long ptr)
1658{
1659 struct thread_trace *ttrace = thread__priv(thread);
1660
1661 ttrace->filename.ptr = ptr;
1662 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1663}
1664
1665static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1666 struct syscall_arg *arg)
1667{
1668 unsigned long ptr = arg->val;
1669
1670 if (!arg->trace->vfs_getname)
1671 return scnprintf(bf, size, "%#x", ptr);
1672
1673 thread__set_filename_pos(arg->thread, bf, ptr);
1674 return 0;
1675}
1676
ae9ed035
ACM
1677static bool trace__filter_duration(struct trace *trace, double t)
1678{
1679 return t < (trace->duration_filter * NSEC_PER_MSEC);
1680}
1681
752fde44
ACM
1682static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1683{
1684 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1685
60c907ab 1686 return fprintf(fp, "%10.3f ", ts);
752fde44
ACM
1687}
1688
f15eb531 1689static bool done = false;
ba209f85 1690static bool interrupted = false;
f15eb531 1691
ba209f85 1692static void sig_handler(int sig)
f15eb531
NK
1693{
1694 done = true;
ba209f85 1695 interrupted = sig == SIGINT;
f15eb531
NK
1696}
1697
752fde44 1698static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
60c907ab 1699 u64 duration, u64 tstamp, FILE *fp)
752fde44
ACM
1700{
1701 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
60c907ab 1702 printed += fprintf_duration(duration, fp);
752fde44 1703
50c95cbd
ACM
1704 if (trace->multiple_threads) {
1705 if (trace->show_comm)
1902efe7 1706 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
38051234 1707 printed += fprintf(fp, "%d ", thread->tid);
50c95cbd 1708 }
752fde44
ACM
1709
1710 return printed;
1711}
1712
c24ff998 1713static int trace__process_event(struct trace *trace, struct machine *machine,
162f0bef 1714 union perf_event *event, struct perf_sample *sample)
752fde44
ACM
1715{
1716 int ret = 0;
1717
1718 switch (event->header.type) {
1719 case PERF_RECORD_LOST:
c24ff998 1720 color_fprintf(trace->output, PERF_COLOR_RED,
752fde44 1721 "LOST %" PRIu64 " events!\n", event->lost.lost);
162f0bef 1722 ret = machine__process_lost_event(machine, event, sample);
3ed5ca2e 1723 break;
752fde44 1724 default:
162f0bef 1725 ret = machine__process_event(machine, event, sample);
752fde44
ACM
1726 break;
1727 }
1728
1729 return ret;
1730}
1731
c24ff998 1732static int trace__tool_process(struct perf_tool *tool,
752fde44 1733 union perf_event *event,
162f0bef 1734 struct perf_sample *sample,
752fde44
ACM
1735 struct machine *machine)
1736{
c24ff998 1737 struct trace *trace = container_of(tool, struct trace, tool);
162f0bef 1738 return trace__process_event(trace, machine, event, sample);
752fde44
ACM
1739}
1740
1741static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1742{
0a7e6d1b 1743 int err = symbol__init(NULL);
752fde44
ACM
1744
1745 if (err)
1746 return err;
1747
8fb598e5
DA
1748 trace->host = machine__new_host();
1749 if (trace->host == NULL)
1750 return -ENOMEM;
752fde44 1751
959c2199 1752 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
706c3da4
ACM
1753 return -errno;
1754
a33fbd56 1755 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
9d9cad76
KL
1756 evlist->threads, trace__tool_process, false,
1757 trace->opts.proc_map_timeout);
752fde44
ACM
1758 if (err)
1759 symbol__exit();
1760
1761 return err;
1762}
1763
13d4ff3e
ACM
1764static int syscall__set_arg_fmts(struct syscall *sc)
1765{
1766 struct format_field *field;
1767 int idx = 0;
1768
f208bd8d 1769 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
13d4ff3e
ACM
1770 if (sc->arg_scnprintf == NULL)
1771 return -1;
1772
1f115cb7
ACM
1773 if (sc->fmt)
1774 sc->arg_parm = sc->fmt->arg_parm;
1775
f208bd8d 1776 for (field = sc->args; field; field = field->next) {
beccb2b5
ACM
1777 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1778 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1779 else if (field->flags & FIELD_IS_POINTER)
13d4ff3e 1780 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
d1d438a3
ACM
1781 else if (strcmp(field->type, "pid_t") == 0)
1782 sc->arg_scnprintf[idx] = SCA_PID;
ba2f22cf
ACM
1783 else if (strcmp(field->type, "umode_t") == 0)
1784 sc->arg_scnprintf[idx] = SCA_MODE_T;
13d4ff3e
ACM
1785 ++idx;
1786 }
1787
1788 return 0;
1789}
1790
514f1c67
ACM
1791static int trace__read_syscall_info(struct trace *trace, int id)
1792{
1793 char tp_name[128];
1794 struct syscall *sc;
fd0db102 1795 const char *name = syscalltbl__name(trace->sctbl, id);
3a531260
ACM
1796
1797 if (name == NULL)
1798 return -1;
514f1c67
ACM
1799
1800 if (id > trace->syscalls.max) {
1801 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1802
1803 if (nsyscalls == NULL)
1804 return -1;
1805
1806 if (trace->syscalls.max != -1) {
1807 memset(nsyscalls + trace->syscalls.max + 1, 0,
1808 (id - trace->syscalls.max) * sizeof(*sc));
1809 } else {
1810 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1811 }
1812
1813 trace->syscalls.table = nsyscalls;
1814 trace->syscalls.max = id;
1815 }
1816
1817 sc = trace->syscalls.table + id;
3a531260 1818 sc->name = name;
2ae3a312 1819
3a531260 1820 sc->fmt = syscall_fmt__find(sc->name);
514f1c67 1821
aec1930b 1822 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
97978b3e 1823 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
aec1930b 1824
8dd2a131 1825 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
aec1930b 1826 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
97978b3e 1827 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
aec1930b 1828 }
514f1c67 1829
8dd2a131 1830 if (IS_ERR(sc->tp_format))
13d4ff3e
ACM
1831 return -1;
1832
f208bd8d
ACM
1833 sc->args = sc->tp_format->format.fields;
1834 sc->nr_args = sc->tp_format->format.nr_fields;
c42de706
TS
1835 /*
1836 * We need to check and discard the first variable '__syscall_nr'
1837 * or 'nr' that mean the syscall number. It is needless here.
1838 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1839 */
1840 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
f208bd8d
ACM
1841 sc->args = sc->args->next;
1842 --sc->nr_args;
1843 }
1844
5089f20e
ACM
1845 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1846
13d4ff3e 1847 return syscall__set_arg_fmts(sc);
514f1c67
ACM
1848}
1849
d0cc439b
ACM
1850static int trace__validate_ev_qualifier(struct trace *trace)
1851{
8b3ce757 1852 int err = 0, i;
d0cc439b
ACM
1853 struct str_node *pos;
1854
8b3ce757
ACM
1855 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1856 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1857 sizeof(trace->ev_qualifier_ids.entries[0]));
1858
1859 if (trace->ev_qualifier_ids.entries == NULL) {
1860 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1861 trace->output);
1862 err = -EINVAL;
1863 goto out;
1864 }
1865
1866 i = 0;
1867
d0cc439b
ACM
1868 strlist__for_each(pos, trace->ev_qualifier) {
1869 const char *sc = pos->s;
fd0db102 1870 int id = syscalltbl__id(trace->sctbl, sc);
d0cc439b 1871
8b3ce757 1872 if (id < 0) {
d0cc439b
ACM
1873 if (err == 0) {
1874 fputs("Error:\tInvalid syscall ", trace->output);
1875 err = -EINVAL;
1876 } else {
1877 fputs(", ", trace->output);
1878 }
1879
1880 fputs(sc, trace->output);
1881 }
8b3ce757
ACM
1882
1883 trace->ev_qualifier_ids.entries[i++] = id;
d0cc439b
ACM
1884 }
1885
1886 if (err < 0) {
1887 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1888 "\nHint:\tand: 'man syscalls'\n", trace->output);
8b3ce757
ACM
1889 zfree(&trace->ev_qualifier_ids.entries);
1890 trace->ev_qualifier_ids.nr = 0;
d0cc439b 1891 }
8b3ce757 1892out:
d0cc439b
ACM
1893 return err;
1894}
1895
55d43bca
DA
1896/*
1897 * args is to be interpreted as a series of longs but we need to handle
1898 * 8-byte unaligned accesses. args points to raw_data within the event
1899 * and raw_data is guaranteed to be 8-byte unaligned because it is
1900 * preceded by raw_size which is a u32. So we need to copy args to a temp
1901 * variable to read it. Most notably this avoids extended load instructions
1902 * on unaligned addresses
1903 */
1904
752fde44 1905static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
55d43bca 1906 unsigned char *args, struct trace *trace,
75b757ca 1907 struct thread *thread)
514f1c67 1908{
514f1c67 1909 size_t printed = 0;
55d43bca
DA
1910 unsigned char *p;
1911 unsigned long val;
514f1c67 1912
f208bd8d 1913 if (sc->args != NULL) {
514f1c67 1914 struct format_field *field;
01533e97
ACM
1915 u8 bit = 1;
1916 struct syscall_arg arg = {
75b757ca
ACM
1917 .idx = 0,
1918 .mask = 0,
1919 .trace = trace,
1920 .thread = thread,
01533e97 1921 };
6e7eeb51 1922
f208bd8d 1923 for (field = sc->args; field;
01533e97
ACM
1924 field = field->next, ++arg.idx, bit <<= 1) {
1925 if (arg.mask & bit)
6e7eeb51 1926 continue;
55d43bca
DA
1927
1928 /* special care for unaligned accesses */
1929 p = args + sizeof(unsigned long) * arg.idx;
1930 memcpy(&val, p, sizeof(val));
1931
4aa58232
ACM
1932 /*
1933 * Suppress this argument if its value is zero and
1934 * and we don't have a string associated in an
1935 * strarray for it.
1936 */
55d43bca 1937 if (val == 0 &&
4aa58232
ACM
1938 !(sc->arg_scnprintf &&
1939 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1940 sc->arg_parm[arg.idx]))
22ae5cf1
ACM
1941 continue;
1942
752fde44 1943 printed += scnprintf(bf + printed, size - printed,
13d4ff3e 1944 "%s%s: ", printed ? ", " : "", field->name);
01533e97 1945 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
55d43bca 1946 arg.val = val;
1f115cb7
ACM
1947 if (sc->arg_parm)
1948 arg.parm = sc->arg_parm[arg.idx];
01533e97
ACM
1949 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1950 size - printed, &arg);
6e7eeb51 1951 } else {
13d4ff3e 1952 printed += scnprintf(bf + printed, size - printed,
55d43bca 1953 "%ld", val);
6e7eeb51 1954 }
514f1c67
ACM
1955 }
1956 } else {
01533e97
ACM
1957 int i = 0;
1958
514f1c67 1959 while (i < 6) {
55d43bca
DA
1960 /* special care for unaligned accesses */
1961 p = args + sizeof(unsigned long) * i;
1962 memcpy(&val, p, sizeof(val));
752fde44
ACM
1963 printed += scnprintf(bf + printed, size - printed,
1964 "%sarg%d: %ld",
55d43bca 1965 printed ? ", " : "", i, val);
514f1c67
ACM
1966 ++i;
1967 }
1968 }
1969
1970 return printed;
1971}
1972
ba3d7dee 1973typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 1974 union perf_event *event,
ba3d7dee
ACM
1975 struct perf_sample *sample);
1976
1977static struct syscall *trace__syscall_info(struct trace *trace,
bf2575c1 1978 struct perf_evsel *evsel, int id)
ba3d7dee 1979{
ba3d7dee
ACM
1980
1981 if (id < 0) {
adaa18bf
ACM
1982
1983 /*
1984 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1985 * before that, leaving at a higher verbosity level till that is
1986 * explained. Reproduced with plain ftrace with:
1987 *
1988 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1989 * grep "NR -1 " /t/trace_pipe
1990 *
1991 * After generating some load on the machine.
1992 */
1993 if (verbose > 1) {
1994 static u64 n;
1995 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1996 id, perf_evsel__name(evsel), ++n);
1997 }
ba3d7dee
ACM
1998 return NULL;
1999 }
2000
2001 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
2002 trace__read_syscall_info(trace, id))
2003 goto out_cant_read;
2004
2005 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
2006 goto out_cant_read;
2007
2008 return &trace->syscalls.table[id];
2009
2010out_cant_read:
7c304ee0
ACM
2011 if (verbose) {
2012 fprintf(trace->output, "Problems reading syscall %d", id);
2013 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
2014 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
2015 fputs(" information\n", trace->output);
2016 }
ba3d7dee
ACM
2017 return NULL;
2018}
2019
bf2575c1
DA
2020static void thread__update_stats(struct thread_trace *ttrace,
2021 int id, struct perf_sample *sample)
2022{
2023 struct int_node *inode;
2024 struct stats *stats;
2025 u64 duration = 0;
2026
2027 inode = intlist__findnew(ttrace->syscall_stats, id);
2028 if (inode == NULL)
2029 return;
2030
2031 stats = inode->priv;
2032 if (stats == NULL) {
2033 stats = malloc(sizeof(struct stats));
2034 if (stats == NULL)
2035 return;
2036 init_stats(stats);
2037 inode->priv = stats;
2038 }
2039
2040 if (ttrace->entry_time && sample->time > ttrace->entry_time)
2041 duration = sample->time - ttrace->entry_time;
2042
2043 update_stats(stats, duration);
2044}
2045
e596663e
ACM
2046static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
2047{
2048 struct thread_trace *ttrace;
2049 u64 duration;
2050 size_t printed;
2051
2052 if (trace->current == NULL)
2053 return 0;
2054
2055 ttrace = thread__priv(trace->current);
2056
2057 if (!ttrace->entry_pending)
2058 return 0;
2059
2060 duration = sample->time - ttrace->entry_time;
2061
2062 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
2063 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
2064 ttrace->entry_pending = false;
2065
2066 return printed;
2067}
2068
ba3d7dee 2069static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 2070 union perf_event *event __maybe_unused,
ba3d7dee
ACM
2071 struct perf_sample *sample)
2072{
752fde44 2073 char *msg;
ba3d7dee 2074 void *args;
752fde44 2075 size_t printed = 0;
2ae3a312 2076 struct thread *thread;
b91fc39f 2077 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
bf2575c1 2078 struct syscall *sc = trace__syscall_info(trace, evsel, id);
2ae3a312
ACM
2079 struct thread_trace *ttrace;
2080
2081 if (sc == NULL)
2082 return -1;
ba3d7dee 2083
8fb598e5 2084 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
c24ff998 2085 ttrace = thread__trace(thread, trace->output);
2ae3a312 2086 if (ttrace == NULL)
b91fc39f 2087 goto out_put;
ba3d7dee 2088
77170988 2089 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
752fde44
ACM
2090
2091 if (ttrace->entry_str == NULL) {
e4d44e83 2092 ttrace->entry_str = malloc(trace__entry_str_size);
752fde44 2093 if (!ttrace->entry_str)
b91fc39f 2094 goto out_put;
752fde44
ACM
2095 }
2096
13f22a2d 2097 if (!trace->summary_only)
6ebad5c1 2098 trace__printf_interrupted_entry(trace, sample);
e596663e 2099
752fde44
ACM
2100 ttrace->entry_time = sample->time;
2101 msg = ttrace->entry_str;
e4d44e83 2102 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
752fde44 2103
e4d44e83 2104 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
75b757ca 2105 args, trace, thread);
752fde44 2106
5089f20e 2107 if (sc->is_exit) {
fd2eabaf 2108 if (!trace->duration_filter && !trace->summary_only) {
c24ff998
ACM
2109 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
2110 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
ae9ed035 2111 }
7f4f8001 2112 } else {
752fde44 2113 ttrace->entry_pending = true;
7f4f8001
ACM
2114 /* See trace__vfs_getname & trace__sys_exit */
2115 ttrace->filename.pending_open = false;
2116 }
ba3d7dee 2117
f3b623b8
ACM
2118 if (trace->current != thread) {
2119 thread__put(trace->current);
2120 trace->current = thread__get(thread);
2121 }
b91fc39f
ACM
2122 err = 0;
2123out_put:
2124 thread__put(thread);
2125 return err;
ba3d7dee
ACM
2126}
2127
202ff968
ACM
2128static int trace__fprintf_callchain(struct trace *trace, struct perf_evsel *evsel,
2129 struct perf_sample *sample)
2130{
2131 struct addr_location al;
2132 /* TODO: user-configurable print_opts */
e20ab86e
ACM
2133 const unsigned int print_opts = EVSEL__PRINT_SYM |
2134 EVSEL__PRINT_DSO |
2135 EVSEL__PRINT_UNKNOWN_AS_ADDR;
202ff968
ACM
2136
2137 if (sample->callchain == NULL)
2138 return 0;
2139
2140 if (machine__resolve(trace->host, &al, sample) < 0) {
2141 pr_err("Problem processing %s callchain, skipping...\n",
2142 perf_evsel__name(evsel));
2143 return 0;
2144 }
2145
2146 return perf_evsel__fprintf_callchain(evsel, sample, &al, 38, print_opts,
2147 scripting_max_stack, trace->output);
2148}
2149
ba3d7dee 2150static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 2151 union perf_event *event __maybe_unused,
ba3d7dee
ACM
2152 struct perf_sample *sample)
2153{
2c82c3ad 2154 long ret;
60c907ab 2155 u64 duration = 0;
2ae3a312 2156 struct thread *thread;
b91fc39f 2157 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
bf2575c1 2158 struct syscall *sc = trace__syscall_info(trace, evsel, id);
2ae3a312
ACM
2159 struct thread_trace *ttrace;
2160
2161 if (sc == NULL)
2162 return -1;
ba3d7dee 2163
8fb598e5 2164 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
c24ff998 2165 ttrace = thread__trace(thread, trace->output);
2ae3a312 2166 if (ttrace == NULL)
b91fc39f 2167 goto out_put;
ba3d7dee 2168
bf2575c1
DA
2169 if (trace->summary)
2170 thread__update_stats(ttrace, id, sample);
2171
77170988 2172 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
ba3d7dee 2173
fd0db102 2174 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
7f4f8001
ACM
2175 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
2176 ttrace->filename.pending_open = false;
c522739d
ACM
2177 ++trace->stats.vfs_getname;
2178 }
2179
752fde44
ACM
2180 ttrace->exit_time = sample->time;
2181
ae9ed035 2182 if (ttrace->entry_time) {
60c907ab 2183 duration = sample->time - ttrace->entry_time;
ae9ed035
ACM
2184 if (trace__filter_duration(trace, duration))
2185 goto out;
2186 } else if (trace->duration_filter)
2187 goto out;
60c907ab 2188
fd2eabaf
DA
2189 if (trace->summary_only)
2190 goto out;
2191
c24ff998 2192 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
752fde44
ACM
2193
2194 if (ttrace->entry_pending) {
c24ff998 2195 fprintf(trace->output, "%-70s", ttrace->entry_str);
752fde44 2196 } else {
c24ff998
ACM
2197 fprintf(trace->output, " ... [");
2198 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
2199 fprintf(trace->output, "]: %s()", sc->name);
752fde44
ACM
2200 }
2201
da3c9a44
ACM
2202 if (sc->fmt == NULL) {
2203signed_print:
2c82c3ad 2204 fprintf(trace->output, ") = %ld", ret);
11c8e39f 2205 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
942a91ed 2206 char bf[STRERR_BUFSIZE];
ba3d7dee
ACM
2207 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
2208 *e = audit_errno_to_name(-ret);
2209
c24ff998 2210 fprintf(trace->output, ") = -1 %s %s", e, emsg);
da3c9a44 2211 } else if (ret == 0 && sc->fmt->timeout)
c24ff998 2212 fprintf(trace->output, ") = 0 Timeout");
04b34729 2213 else if (sc->fmt->hexret)
2c82c3ad 2214 fprintf(trace->output, ") = %#lx", ret);
11c8e39f
ACM
2215 else if (sc->fmt->errpid) {
2216 struct thread *child = machine__find_thread(trace->host, ret, ret);
2217
2218 if (child != NULL) {
2219 fprintf(trace->output, ") = %ld", ret);
2220 if (child->comm_set)
2221 fprintf(trace->output, " (%s)", thread__comm_str(child));
2222 thread__put(child);
2223 }
2224 } else
da3c9a44 2225 goto signed_print;
ba3d7dee 2226
c24ff998 2227 fputc('\n', trace->output);
566a0885 2228
202ff968 2229 trace__fprintf_callchain(trace, evsel, sample);
ae9ed035 2230out:
752fde44 2231 ttrace->entry_pending = false;
b91fc39f
ACM
2232 err = 0;
2233out_put:
2234 thread__put(thread);
2235 return err;
ba3d7dee
ACM
2236}
2237
c522739d 2238static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 2239 union perf_event *event __maybe_unused,
c522739d
ACM
2240 struct perf_sample *sample)
2241{
f994592d
ACM
2242 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2243 struct thread_trace *ttrace;
2244 size_t filename_len, entry_str_len, to_move;
2245 ssize_t remaining_space;
2246 char *pos;
7f4f8001 2247 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
f994592d
ACM
2248
2249 if (!thread)
2250 goto out;
2251
2252 ttrace = thread__priv(thread);
2253 if (!ttrace)
2254 goto out;
2255
7f4f8001
ACM
2256 filename_len = strlen(filename);
2257
2258 if (ttrace->filename.namelen < filename_len) {
2259 char *f = realloc(ttrace->filename.name, filename_len + 1);
2260
2261 if (f == NULL)
2262 goto out;
2263
2264 ttrace->filename.namelen = filename_len;
2265 ttrace->filename.name = f;
2266 }
2267
2268 strcpy(ttrace->filename.name, filename);
2269 ttrace->filename.pending_open = true;
2270
f994592d
ACM
2271 if (!ttrace->filename.ptr)
2272 goto out;
2273
2274 entry_str_len = strlen(ttrace->entry_str);
2275 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2276 if (remaining_space <= 0)
2277 goto out;
2278
f994592d
ACM
2279 if (filename_len > (size_t)remaining_space) {
2280 filename += filename_len - remaining_space;
2281 filename_len = remaining_space;
2282 }
2283
2284 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2285 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2286 memmove(pos + filename_len, pos, to_move);
2287 memcpy(pos, filename, filename_len);
2288
2289 ttrace->filename.ptr = 0;
2290 ttrace->filename.entry_str_pos = 0;
2291out:
c522739d
ACM
2292 return 0;
2293}
2294
1302d88e 2295static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 2296 union perf_event *event __maybe_unused,
1302d88e
ACM
2297 struct perf_sample *sample)
2298{
2299 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2300 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
8fb598e5 2301 struct thread *thread = machine__findnew_thread(trace->host,
314add6b
AH
2302 sample->pid,
2303 sample->tid);
c24ff998 2304 struct thread_trace *ttrace = thread__trace(thread, trace->output);
1302d88e
ACM
2305
2306 if (ttrace == NULL)
2307 goto out_dump;
2308
2309 ttrace->runtime_ms += runtime_ms;
2310 trace->runtime_ms += runtime_ms;
b91fc39f 2311 thread__put(thread);
1302d88e
ACM
2312 return 0;
2313
2314out_dump:
c24ff998 2315 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
1302d88e
ACM
2316 evsel->name,
2317 perf_evsel__strval(evsel, sample, "comm"),
2318 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2319 runtime,
2320 perf_evsel__intval(evsel, sample, "vruntime"));
b91fc39f 2321 thread__put(thread);
1302d88e
ACM
2322 return 0;
2323}
2324
1d6c9407
WN
2325static void bpf_output__printer(enum binary_printer_ops op,
2326 unsigned int val, void *extra)
2327{
2328 FILE *output = extra;
2329 unsigned char ch = (unsigned char)val;
2330
2331 switch (op) {
2332 case BINARY_PRINT_CHAR_DATA:
2333 fprintf(output, "%c", isprint(ch) ? ch : '.');
2334 break;
2335 case BINARY_PRINT_DATA_BEGIN:
2336 case BINARY_PRINT_LINE_BEGIN:
2337 case BINARY_PRINT_ADDR:
2338 case BINARY_PRINT_NUM_DATA:
2339 case BINARY_PRINT_NUM_PAD:
2340 case BINARY_PRINT_SEP:
2341 case BINARY_PRINT_CHAR_PAD:
2342 case BINARY_PRINT_LINE_END:
2343 case BINARY_PRINT_DATA_END:
2344 default:
2345 break;
2346 }
2347}
2348
2349static void bpf_output__fprintf(struct trace *trace,
2350 struct perf_sample *sample)
2351{
2352 print_binary(sample->raw_data, sample->raw_size, 8,
2353 bpf_output__printer, trace->output);
2354}
2355
14a052df
ACM
2356static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2357 union perf_event *event __maybe_unused,
2358 struct perf_sample *sample)
2359{
2360 trace__printf_interrupted_entry(trace, sample);
2361 trace__fprintf_tstamp(trace, sample->time, trace->output);
0808921a
ACM
2362
2363 if (trace->trace_syscalls)
2364 fprintf(trace->output, "( ): ");
2365
2366 fprintf(trace->output, "%s:", evsel->name);
14a052df 2367
1d6c9407
WN
2368 if (perf_evsel__is_bpf_output(evsel)) {
2369 bpf_output__fprintf(trace, sample);
2370 } else if (evsel->tp_format) {
14a052df
ACM
2371 event_format__fprintf(evsel->tp_format, sample->cpu,
2372 sample->raw_data, sample->raw_size,
2373 trace->output);
2374 }
2375
2376 fprintf(trace->output, ")\n");
202ff968
ACM
2377
2378 trace__fprintf_callchain(trace, evsel, sample);
2379
14a052df
ACM
2380 return 0;
2381}
2382
598d02c5
SF
2383static void print_location(FILE *f, struct perf_sample *sample,
2384 struct addr_location *al,
2385 bool print_dso, bool print_sym)
2386{
2387
2388 if ((verbose || print_dso) && al->map)
2389 fprintf(f, "%s@", al->map->dso->long_name);
2390
2391 if ((verbose || print_sym) && al->sym)
4414a3c5 2392 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
598d02c5
SF
2393 al->addr - al->sym->start);
2394 else if (al->map)
4414a3c5 2395 fprintf(f, "0x%" PRIx64, al->addr);
598d02c5 2396 else
4414a3c5 2397 fprintf(f, "0x%" PRIx64, sample->addr);
598d02c5
SF
2398}
2399
2400static int trace__pgfault(struct trace *trace,
2401 struct perf_evsel *evsel,
473398a2 2402 union perf_event *event __maybe_unused,
598d02c5
SF
2403 struct perf_sample *sample)
2404{
2405 struct thread *thread;
598d02c5
SF
2406 struct addr_location al;
2407 char map_type = 'd';
a2ea67d7 2408 struct thread_trace *ttrace;
b91fc39f 2409 int err = -1;
598d02c5
SF
2410
2411 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
a2ea67d7
SF
2412 ttrace = thread__trace(thread, trace->output);
2413 if (ttrace == NULL)
b91fc39f 2414 goto out_put;
a2ea67d7
SF
2415
2416 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2417 ttrace->pfmaj++;
2418 else
2419 ttrace->pfmin++;
2420
2421 if (trace->summary_only)
b91fc39f 2422 goto out;
598d02c5 2423
473398a2 2424 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
598d02c5
SF
2425 sample->ip, &al);
2426
2427 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2428
2429 fprintf(trace->output, "%sfault [",
2430 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2431 "maj" : "min");
2432
2433 print_location(trace->output, sample, &al, false, true);
2434
2435 fprintf(trace->output, "] => ");
2436
473398a2 2437 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
598d02c5
SF
2438 sample->addr, &al);
2439
2440 if (!al.map) {
473398a2 2441 thread__find_addr_location(thread, sample->cpumode,
598d02c5
SF
2442 MAP__FUNCTION, sample->addr, &al);
2443
2444 if (al.map)
2445 map_type = 'x';
2446 else
2447 map_type = '?';
2448 }
2449
2450 print_location(trace->output, sample, &al, true, false);
2451
2452 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
b91fc39f
ACM
2453out:
2454 err = 0;
2455out_put:
2456 thread__put(thread);
2457 return err;
598d02c5
SF
2458}
2459
bdc89661
DA
2460static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2461{
2462 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2463 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2464 return false;
2465
2466 if (trace->pid_list || trace->tid_list)
2467 return true;
2468
2469 return false;
2470}
2471
e6001980 2472static void trace__set_base_time(struct trace *trace,
8a07a809 2473 struct perf_evsel *evsel,
e6001980
ACM
2474 struct perf_sample *sample)
2475{
8a07a809
ACM
2476 /*
2477 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2478 * and don't use sample->time unconditionally, we may end up having
2479 * some other event in the future without PERF_SAMPLE_TIME for good
2480 * reason, i.e. we may not be interested in its timestamps, just in
2481 * it taking place, picking some piece of information when it
2482 * appears in our event stream (vfs_getname comes to mind).
2483 */
2484 if (trace->base_time == 0 && !trace->full_time &&
2485 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
e6001980
ACM
2486 trace->base_time = sample->time;
2487}
2488
6810fc91 2489static int trace__process_sample(struct perf_tool *tool,
0c82adcf 2490 union perf_event *event,
6810fc91
DA
2491 struct perf_sample *sample,
2492 struct perf_evsel *evsel,
2493 struct machine *machine __maybe_unused)
2494{
2495 struct trace *trace = container_of(tool, struct trace, tool);
2496 int err = 0;
2497
744a9719 2498 tracepoint_handler handler = evsel->handler;
6810fc91 2499
bdc89661
DA
2500 if (skip_sample(trace, sample))
2501 return 0;
2502
e6001980 2503 trace__set_base_time(trace, evsel, sample);
6810fc91 2504
3160565f
DA
2505 if (handler) {
2506 ++trace->nr_events;
0c82adcf 2507 handler(trace, evsel, event, sample);
3160565f 2508 }
6810fc91
DA
2509
2510 return err;
2511}
2512
bdc89661
DA
2513static int parse_target_str(struct trace *trace)
2514{
2515 if (trace->opts.target.pid) {
2516 trace->pid_list = intlist__new(trace->opts.target.pid);
2517 if (trace->pid_list == NULL) {
2518 pr_err("Error parsing process id string\n");
2519 return -EINVAL;
2520 }
2521 }
2522
2523 if (trace->opts.target.tid) {
2524 trace->tid_list = intlist__new(trace->opts.target.tid);
2525 if (trace->tid_list == NULL) {
2526 pr_err("Error parsing thread id string\n");
2527 return -EINVAL;
2528 }
2529 }
2530
2531 return 0;
2532}
2533
1e28fe0a 2534static int trace__record(struct trace *trace, int argc, const char **argv)
5e2485b1
DA
2535{
2536 unsigned int rec_argc, i, j;
2537 const char **rec_argv;
2538 const char * const record_args[] = {
2539 "record",
2540 "-R",
2541 "-m", "1024",
2542 "-c", "1",
5e2485b1
DA
2543 };
2544
1e28fe0a
SF
2545 const char * const sc_args[] = { "-e", };
2546 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2547 const char * const majpf_args[] = { "-e", "major-faults" };
2548 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2549 const char * const minpf_args[] = { "-e", "minor-faults" };
2550 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2551
9aca7f17 2552 /* +1 is for the event string below */
1e28fe0a
SF
2553 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2554 majpf_args_nr + minpf_args_nr + argc;
5e2485b1
DA
2555 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2556
2557 if (rec_argv == NULL)
2558 return -ENOMEM;
2559
1e28fe0a 2560 j = 0;
5e2485b1 2561 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1e28fe0a
SF
2562 rec_argv[j++] = record_args[i];
2563
e281a960
SF
2564 if (trace->trace_syscalls) {
2565 for (i = 0; i < sc_args_nr; i++)
2566 rec_argv[j++] = sc_args[i];
2567
2568 /* event string may be different for older kernels - e.g., RHEL6 */
2569 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2570 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2571 else if (is_valid_tracepoint("syscalls:sys_enter"))
2572 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2573 else {
2574 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2575 return -1;
2576 }
9aca7f17 2577 }
9aca7f17 2578
1e28fe0a
SF
2579 if (trace->trace_pgfaults & TRACE_PFMAJ)
2580 for (i = 0; i < majpf_args_nr; i++)
2581 rec_argv[j++] = majpf_args[i];
2582
2583 if (trace->trace_pgfaults & TRACE_PFMIN)
2584 for (i = 0; i < minpf_args_nr; i++)
2585 rec_argv[j++] = minpf_args[i];
2586
2587 for (i = 0; i < (unsigned int)argc; i++)
2588 rec_argv[j++] = argv[i];
5e2485b1 2589
1e28fe0a 2590 return cmd_record(j, rec_argv, NULL);
5e2485b1
DA
2591}
2592
bf2575c1
DA
2593static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2594
08c98776 2595static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
c522739d 2596{
ef503831 2597 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
8dd2a131
JO
2598
2599 if (IS_ERR(evsel))
08c98776 2600 return false;
c522739d
ACM
2601
2602 if (perf_evsel__field(evsel, "pathname") == NULL) {
2603 perf_evsel__delete(evsel);
08c98776 2604 return false;
c522739d
ACM
2605 }
2606
744a9719 2607 evsel->handler = trace__vfs_getname;
c522739d 2608 perf_evlist__add(evlist, evsel);
08c98776 2609 return true;
c522739d
ACM
2610}
2611
598d02c5
SF
2612static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2613 u64 config)
2614{
2615 struct perf_evsel *evsel;
2616 struct perf_event_attr attr = {
2617 .type = PERF_TYPE_SOFTWARE,
2618 .mmap_data = 1,
598d02c5
SF
2619 };
2620
2621 attr.config = config;
0524798c 2622 attr.sample_period = 1;
598d02c5
SF
2623
2624 event_attr_init(&attr);
2625
2626 evsel = perf_evsel__new(&attr);
2627 if (!evsel)
2628 return -ENOMEM;
2629
2630 evsel->handler = trace__pgfault;
2631 perf_evlist__add(evlist, evsel);
2632
2633 return 0;
2634}
2635
ddbb1b13
ACM
2636static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2637{
2638 const u32 type = event->header.type;
2639 struct perf_evsel *evsel;
2640
ddbb1b13
ACM
2641 if (type != PERF_RECORD_SAMPLE) {
2642 trace__process_event(trace, trace->host, event, sample);
2643 return;
2644 }
2645
2646 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2647 if (evsel == NULL) {
2648 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2649 return;
2650 }
2651
e6001980
ACM
2652 trace__set_base_time(trace, evsel, sample);
2653
ddbb1b13
ACM
2654 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2655 sample->raw_data == NULL) {
2656 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2657 perf_evsel__name(evsel), sample->tid,
2658 sample->cpu, sample->raw_size);
2659 } else {
2660 tracepoint_handler handler = evsel->handler;
2661 handler(trace, evsel, event, sample);
2662 }
2663}
2664
c27366f0
ACM
2665static int trace__add_syscall_newtp(struct trace *trace)
2666{
2667 int ret = -1;
2668 struct perf_evlist *evlist = trace->evlist;
2669 struct perf_evsel *sys_enter, *sys_exit;
2670
2671 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2672 if (sys_enter == NULL)
2673 goto out;
2674
2675 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2676 goto out_delete_sys_enter;
2677
2678 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2679 if (sys_exit == NULL)
2680 goto out_delete_sys_enter;
2681
2682 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2683 goto out_delete_sys_exit;
2684
2685 perf_evlist__add(evlist, sys_enter);
2686 perf_evlist__add(evlist, sys_exit);
2687
44621819
ACM
2688 if (trace->opts.callgraph_set && !trace->kernel_syscallchains) {
2689 /*
2690 * We're interested only in the user space callchain
2691 * leading to the syscall, allow overriding that for
2692 * debugging reasons using --kernel_syscall_callchains
2693 */
2694 sys_exit->attr.exclude_callchain_kernel = 1;
2695 }
2696
8b3ce757
ACM
2697 trace->syscalls.events.sys_enter = sys_enter;
2698 trace->syscalls.events.sys_exit = sys_exit;
c27366f0
ACM
2699
2700 ret = 0;
2701out:
2702 return ret;
2703
2704out_delete_sys_exit:
2705 perf_evsel__delete_priv(sys_exit);
2706out_delete_sys_enter:
2707 perf_evsel__delete_priv(sys_enter);
2708 goto out;
2709}
2710
19867b61
ACM
2711static int trace__set_ev_qualifier_filter(struct trace *trace)
2712{
2713 int err = -1;
2714 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2715 trace->ev_qualifier_ids.nr,
2716 trace->ev_qualifier_ids.entries);
2717
2718 if (filter == NULL)
2719 goto out_enomem;
2720
2721 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2722 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2723
2724 free(filter);
2725out:
2726 return err;
2727out_enomem:
2728 errno = ENOMEM;
2729 goto out;
2730}
c27366f0 2731
f15eb531 2732static int trace__run(struct trace *trace, int argc, const char **argv)
514f1c67 2733{
14a052df 2734 struct perf_evlist *evlist = trace->evlist;
94ad89bc 2735 struct perf_evsel *evsel;
efd5745e
ACM
2736 int err = -1, i;
2737 unsigned long before;
f15eb531 2738 const bool forks = argc > 0;
46fb3c21 2739 bool draining = false;
514f1c67 2740
75b757ca
ACM
2741 trace->live = true;
2742
c27366f0 2743 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
801c67b0 2744 goto out_error_raw_syscalls;
514f1c67 2745
e281a960 2746 if (trace->trace_syscalls)
08c98776 2747 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
c522739d 2748
598d02c5 2749 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
e2726d99 2750 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
5ed08dae 2751 goto out_error_mem;
e2726d99 2752 }
598d02c5
SF
2753
2754 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2755 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
5ed08dae 2756 goto out_error_mem;
598d02c5 2757
1302d88e 2758 if (trace->sched &&
2cc990ba
ACM
2759 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2760 trace__sched_stat_runtime))
2761 goto out_error_sched_stat_runtime;
1302d88e 2762
514f1c67
ACM
2763 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2764 if (err < 0) {
c24ff998 2765 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
514f1c67
ACM
2766 goto out_delete_evlist;
2767 }
2768
752fde44
ACM
2769 err = trace__symbols_init(trace, evlist);
2770 if (err < 0) {
c24ff998 2771 fprintf(trace->output, "Problems initializing symbol libraries!\n");
03ad9747 2772 goto out_delete_evlist;
752fde44
ACM
2773 }
2774
fde54b78
ACM
2775 perf_evlist__config(evlist, &trace->opts, NULL);
2776
2777 if (trace->opts.callgraph_set && trace->syscalls.events.sys_exit) {
2778 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2779 &trace->opts, &callchain_param);
2780 /*
2781 * Now we have evsels with different sample_ids, use
2782 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2783 * from a fixed position in each ring buffer record.
2784 *
2785 * As of this the changeset introducing this comment, this
2786 * isn't strictly needed, as the fields that can come before
2787 * PERF_SAMPLE_ID are all used, but we'll probably disable
2788 * some of those for things like copying the payload of
2789 * pointer syscall arguments, and for vfs_getname we don't
2790 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2791 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2792 */
2793 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2794 perf_evlist__reset_sample_bit(evlist, ID);
2795 }
514f1c67 2796
f15eb531
NK
2797 signal(SIGCHLD, sig_handler);
2798 signal(SIGINT, sig_handler);
2799
2800 if (forks) {
6ef73ec4 2801 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
735f7e0b 2802 argv, false, NULL);
f15eb531 2803 if (err < 0) {
c24ff998 2804 fprintf(trace->output, "Couldn't run the workload!\n");
03ad9747 2805 goto out_delete_evlist;
f15eb531
NK
2806 }
2807 }
2808
514f1c67 2809 err = perf_evlist__open(evlist);
a8f23d8f
ACM
2810 if (err < 0)
2811 goto out_error_open;
514f1c67 2812
ba504235
WN
2813 err = bpf__apply_obj_config();
2814 if (err) {
2815 char errbuf[BUFSIZ];
2816
2817 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2818 pr_err("ERROR: Apply config to BPF failed: %s\n",
2819 errbuf);
2820 goto out_error_open;
2821 }
2822
241b057c
ACM
2823 /*
2824 * Better not use !target__has_task() here because we need to cover the
2825 * case where no threads were specified in the command line, but a
2826 * workload was, and in that case we will fill in the thread_map when
2827 * we fork the workload in perf_evlist__prepare_workload.
2828 */
f078c385
ACM
2829 if (trace->filter_pids.nr > 0)
2830 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
e13798c7 2831 else if (thread_map__pid(evlist->threads, 0) == -1)
f078c385
ACM
2832 err = perf_evlist__set_filter_pid(evlist, getpid());
2833
94ad89bc
ACM
2834 if (err < 0)
2835 goto out_error_mem;
2836
19867b61
ACM
2837 if (trace->ev_qualifier_ids.nr > 0) {
2838 err = trace__set_ev_qualifier_filter(trace);
2839 if (err < 0)
2840 goto out_errno;
19867b61 2841
2e5e5f87
ACM
2842 pr_debug("event qualifier tracepoint filter: %s\n",
2843 trace->syscalls.events.sys_exit->filter);
2844 }
19867b61 2845
94ad89bc
ACM
2846 err = perf_evlist__apply_filters(evlist, &evsel);
2847 if (err < 0)
2848 goto out_error_apply_filters;
241b057c 2849
f885037e 2850 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
e09b18d4
ACM
2851 if (err < 0)
2852 goto out_error_mmap;
514f1c67 2853
cb24d01d
ACM
2854 if (!target__none(&trace->opts.target))
2855 perf_evlist__enable(evlist);
2856
f15eb531
NK
2857 if (forks)
2858 perf_evlist__start_workload(evlist);
2859
e13798c7 2860 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
42052bea
ACM
2861 evlist->threads->nr > 1 ||
2862 perf_evlist__first(evlist)->attr.inherit;
514f1c67 2863again:
efd5745e 2864 before = trace->nr_events;
514f1c67
ACM
2865
2866 for (i = 0; i < evlist->nr_mmaps; i++) {
2867 union perf_event *event;
2868
2869 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
514f1c67 2870 struct perf_sample sample;
514f1c67 2871
efd5745e 2872 ++trace->nr_events;
514f1c67 2873
514f1c67
ACM
2874 err = perf_evlist__parse_sample(evlist, event, &sample);
2875 if (err) {
c24ff998 2876 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
8e50d384 2877 goto next_event;
514f1c67
ACM
2878 }
2879
ddbb1b13 2880 trace__handle_event(trace, event, &sample);
8e50d384
ZZ
2881next_event:
2882 perf_evlist__mmap_consume(evlist, i);
20c5f10e 2883
ba209f85
ACM
2884 if (interrupted)
2885 goto out_disable;
02ac5421
ACM
2886
2887 if (done && !draining) {
2888 perf_evlist__disable(evlist);
2889 draining = true;
2890 }
514f1c67
ACM
2891 }
2892 }
2893
efd5745e 2894 if (trace->nr_events == before) {
ba209f85 2895 int timeout = done ? 100 : -1;
f15eb531 2896
46fb3c21
ACM
2897 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2898 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2899 draining = true;
2900
ba209f85 2901 goto again;
46fb3c21 2902 }
ba209f85
ACM
2903 } else {
2904 goto again;
f15eb531
NK
2905 }
2906
ba209f85 2907out_disable:
f3b623b8
ACM
2908 thread__zput(trace->current);
2909
ba209f85 2910 perf_evlist__disable(evlist);
514f1c67 2911
c522739d
ACM
2912 if (!err) {
2913 if (trace->summary)
2914 trace__fprintf_thread_summary(trace, trace->output);
2915
2916 if (trace->show_tool_stats) {
2917 fprintf(trace->output, "Stats:\n "
2918 " vfs_getname : %" PRIu64 "\n"
2919 " proc_getname: %" PRIu64 "\n",
2920 trace->stats.vfs_getname,
2921 trace->stats.proc_getname);
2922 }
2923 }
bf2575c1 2924
514f1c67
ACM
2925out_delete_evlist:
2926 perf_evlist__delete(evlist);
14a052df 2927 trace->evlist = NULL;
75b757ca 2928 trace->live = false;
514f1c67 2929 return err;
6ef068cb
ACM
2930{
2931 char errbuf[BUFSIZ];
a8f23d8f 2932
2cc990ba 2933out_error_sched_stat_runtime:
988bdb31 2934 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
2cc990ba
ACM
2935 goto out_error;
2936
801c67b0 2937out_error_raw_syscalls:
988bdb31 2938 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
a8f23d8f
ACM
2939 goto out_error;
2940
e09b18d4
ACM
2941out_error_mmap:
2942 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2943 goto out_error;
2944
a8f23d8f
ACM
2945out_error_open:
2946 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2947
2948out_error:
6ef068cb 2949 fprintf(trace->output, "%s\n", errbuf);
87f91868 2950 goto out_delete_evlist;
94ad89bc
ACM
2951
2952out_error_apply_filters:
2953 fprintf(trace->output,
2954 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2955 evsel->filter, perf_evsel__name(evsel), errno,
2956 strerror_r(errno, errbuf, sizeof(errbuf)));
2957 goto out_delete_evlist;
514f1c67 2958}
5ed08dae
ACM
2959out_error_mem:
2960 fprintf(trace->output, "Not enough memory to run!\n");
2961 goto out_delete_evlist;
19867b61
ACM
2962
2963out_errno:
2964 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2965 goto out_delete_evlist;
a8f23d8f 2966}
514f1c67 2967
6810fc91
DA
2968static int trace__replay(struct trace *trace)
2969{
2970 const struct perf_evsel_str_handler handlers[] = {
c522739d 2971 { "probe:vfs_getname", trace__vfs_getname, },
6810fc91 2972 };
f5fc1412
JO
2973 struct perf_data_file file = {
2974 .path = input_name,
2975 .mode = PERF_DATA_MODE_READ,
e366a6d8 2976 .force = trace->force,
f5fc1412 2977 };
6810fc91 2978 struct perf_session *session;
003824e8 2979 struct perf_evsel *evsel;
6810fc91
DA
2980 int err = -1;
2981
2982 trace->tool.sample = trace__process_sample;
2983 trace->tool.mmap = perf_event__process_mmap;
384c671e 2984 trace->tool.mmap2 = perf_event__process_mmap2;
6810fc91
DA
2985 trace->tool.comm = perf_event__process_comm;
2986 trace->tool.exit = perf_event__process_exit;
2987 trace->tool.fork = perf_event__process_fork;
2988 trace->tool.attr = perf_event__process_attr;
2989 trace->tool.tracing_data = perf_event__process_tracing_data;
2990 trace->tool.build_id = perf_event__process_build_id;
2991
0a8cb85c 2992 trace->tool.ordered_events = true;
6810fc91
DA
2993 trace->tool.ordering_requires_timestamps = true;
2994
2995 /* add tid to output */
2996 trace->multiple_threads = true;
2997
f5fc1412 2998 session = perf_session__new(&file, false, &trace->tool);
6810fc91 2999 if (session == NULL)
52e02834 3000 return -1;
6810fc91 3001
0a7e6d1b 3002 if (symbol__init(&session->header.env) < 0)
cb2ffae2
NK
3003 goto out;
3004
8fb598e5
DA
3005 trace->host = &session->machines.host;
3006
6810fc91
DA
3007 err = perf_session__set_tracepoints_handlers(session, handlers);
3008 if (err)
3009 goto out;
3010
003824e8
NK
3011 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
3012 "raw_syscalls:sys_enter");
9aca7f17
DA
3013 /* older kernels have syscalls tp versus raw_syscalls */
3014 if (evsel == NULL)
3015 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
3016 "syscalls:sys_enter");
003824e8 3017
e281a960
SF
3018 if (evsel &&
3019 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
3020 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
003824e8
NK
3021 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
3022 goto out;
3023 }
3024
3025 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
3026 "raw_syscalls:sys_exit");
9aca7f17
DA
3027 if (evsel == NULL)
3028 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
3029 "syscalls:sys_exit");
e281a960
SF
3030 if (evsel &&
3031 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
3032 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
003824e8 3033 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
6810fc91
DA
3034 goto out;
3035 }
3036
1e28fe0a
SF
3037 evlist__for_each(session->evlist, evsel) {
3038 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
3039 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
3040 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
3041 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
3042 evsel->handler = trace__pgfault;
3043 }
3044
bdc89661
DA
3045 err = parse_target_str(trace);
3046 if (err != 0)
3047 goto out;
3048
6810fc91
DA
3049 setup_pager();
3050
b7b61cbe 3051 err = perf_session__process_events(session);
6810fc91
DA
3052 if (err)
3053 pr_err("Failed to process events, error %d", err);
3054
bf2575c1
DA
3055 else if (trace->summary)
3056 trace__fprintf_thread_summary(trace, trace->output);
3057
6810fc91
DA
3058out:
3059 perf_session__delete(session);
3060
3061 return err;
3062}
3063
1302d88e
ACM
3064static size_t trace__fprintf_threads_header(FILE *fp)
3065{
3066 size_t printed;
3067
99ff7150 3068 printed = fprintf(fp, "\n Summary of events:\n\n");
bf2575c1
DA
3069
3070 return printed;
3071}
3072
3073static size_t thread__dump_stats(struct thread_trace *ttrace,
3074 struct trace *trace, FILE *fp)
3075{
3076 struct stats *stats;
3077 size_t printed = 0;
3078 struct syscall *sc;
3079 struct int_node *inode = intlist__first(ttrace->syscall_stats);
3080
3081 if (inode == NULL)
3082 return 0;
3083
3084 printed += fprintf(fp, "\n");
3085
834fd46d
MW
3086 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
3087 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
3088 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
99ff7150 3089
bf2575c1
DA
3090 /* each int_node is a syscall */
3091 while (inode) {
3092 stats = inode->priv;
3093 if (stats) {
3094 double min = (double)(stats->min) / NSEC_PER_MSEC;
3095 double max = (double)(stats->max) / NSEC_PER_MSEC;
3096 double avg = avg_stats(stats);
3097 double pct;
3098 u64 n = (u64) stats->n;
3099
3100 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
3101 avg /= NSEC_PER_MSEC;
3102
3103 sc = &trace->syscalls.table[inode->i];
99ff7150 3104 printed += fprintf(fp, " %-15s", sc->name);
834fd46d
MW
3105 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
3106 n, avg * n, min, avg);
27a778b5 3107 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
bf2575c1
DA
3108 }
3109
3110 inode = intlist__next(inode);
3111 }
3112
3113 printed += fprintf(fp, "\n\n");
1302d88e
ACM
3114
3115 return printed;
3116}
3117
896cbb56
DA
3118/* struct used to pass data to per-thread function */
3119struct summary_data {
3120 FILE *fp;
3121 struct trace *trace;
3122 size_t printed;
3123};
3124
3125static int trace__fprintf_one_thread(struct thread *thread, void *priv)
3126{
3127 struct summary_data *data = priv;
3128 FILE *fp = data->fp;
3129 size_t printed = data->printed;
3130 struct trace *trace = data->trace;
89dceb22 3131 struct thread_trace *ttrace = thread__priv(thread);
896cbb56
DA
3132 double ratio;
3133
3134 if (ttrace == NULL)
3135 return 0;
3136
3137 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
3138
15e65c69 3139 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
99ff7150 3140 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
15e65c69 3141 printed += fprintf(fp, "%.1f%%", ratio);
a2ea67d7
SF
3142 if (ttrace->pfmaj)
3143 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
3144 if (ttrace->pfmin)
3145 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
99ff7150 3146 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
bf2575c1 3147 printed += thread__dump_stats(ttrace, trace, fp);
896cbb56
DA
3148
3149 data->printed += printed;
3150
3151 return 0;
3152}
3153
1302d88e
ACM
3154static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
3155{
896cbb56
DA
3156 struct summary_data data = {
3157 .fp = fp,
3158 .trace = trace
3159 };
3160 data.printed = trace__fprintf_threads_header(fp);
1302d88e 3161
896cbb56
DA
3162 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
3163
3164 return data.printed;
1302d88e
ACM
3165}
3166
ae9ed035
ACM
3167static int trace__set_duration(const struct option *opt, const char *str,
3168 int unset __maybe_unused)
3169{
3170 struct trace *trace = opt->value;
3171
3172 trace->duration_filter = atof(str);
3173 return 0;
3174}
3175
f078c385
ACM
3176static int trace__set_filter_pids(const struct option *opt, const char *str,
3177 int unset __maybe_unused)
3178{
3179 int ret = -1;
3180 size_t i;
3181 struct trace *trace = opt->value;
3182 /*
3183 * FIXME: introduce a intarray class, plain parse csv and create a
3184 * { int nr, int entries[] } struct...
3185 */
3186 struct intlist *list = intlist__new(str);
3187
3188 if (list == NULL)
3189 return -1;
3190
3191 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
3192 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
3193
3194 if (trace->filter_pids.entries == NULL)
3195 goto out;
3196
3197 trace->filter_pids.entries[0] = getpid();
3198
3199 for (i = 1; i < trace->filter_pids.nr; ++i)
3200 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
3201
3202 intlist__delete(list);
3203 ret = 0;
3204out:
3205 return ret;
3206}
3207
c24ff998
ACM
3208static int trace__open_output(struct trace *trace, const char *filename)
3209{
3210 struct stat st;
3211
3212 if (!stat(filename, &st) && st.st_size) {
3213 char oldname[PATH_MAX];
3214
3215 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
3216 unlink(oldname);
3217 rename(filename, oldname);
3218 }
3219
3220 trace->output = fopen(filename, "w");
3221
3222 return trace->output == NULL ? -errno : 0;
3223}
3224
598d02c5
SF
3225static int parse_pagefaults(const struct option *opt, const char *str,
3226 int unset __maybe_unused)
3227{
3228 int *trace_pgfaults = opt->value;
3229
3230 if (strcmp(str, "all") == 0)
3231 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
3232 else if (strcmp(str, "maj") == 0)
3233 *trace_pgfaults |= TRACE_PFMAJ;
3234 else if (strcmp(str, "min") == 0)
3235 *trace_pgfaults |= TRACE_PFMIN;
3236 else
3237 return -1;
3238
3239 return 0;
3240}
3241
14a052df
ACM
3242static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3243{
3244 struct perf_evsel *evsel;
3245
3246 evlist__for_each(evlist, evsel)
3247 evsel->handler = handler;
3248}
3249
514f1c67
ACM
3250int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3251{
6fdd9cb7 3252 const char *trace_usage[] = {
f15eb531
NK
3253 "perf trace [<options>] [<command>]",
3254 "perf trace [<options>] -- <command> [<options>]",
5e2485b1
DA
3255 "perf trace record [<options>] [<command>]",
3256 "perf trace record [<options>] -- <command> [<options>]",
514f1c67
ACM
3257 NULL
3258 };
3259 struct trace trace = {
514f1c67
ACM
3260 .syscalls = {
3261 . max = -1,
3262 },
3263 .opts = {
3264 .target = {
3265 .uid = UINT_MAX,
3266 .uses_mmap = true,
3267 },
3268 .user_freq = UINT_MAX,
3269 .user_interval = ULLONG_MAX,
509051ea 3270 .no_buffering = true,
38d5447d 3271 .mmap_pages = UINT_MAX,
9d9cad76 3272 .proc_map_timeout = 500,
514f1c67 3273 },
007d66a0 3274 .output = stderr,
50c95cbd 3275 .show_comm = true,
e281a960 3276 .trace_syscalls = true,
44621819 3277 .kernel_syscallchains = false,
514f1c67 3278 };
c24ff998 3279 const char *output_name = NULL;
2ae3a312 3280 const char *ev_qualifier_str = NULL;
514f1c67 3281 const struct option trace_options[] = {
14a052df
ACM
3282 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3283 "event selector. use 'perf list' to list available events",
3284 parse_events_option),
50c95cbd
ACM
3285 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3286 "show the thread COMM next to its id"),
c522739d 3287 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
d303e85a 3288 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
c24ff998 3289 OPT_STRING('o', "output", &output_name, "file", "output file name"),
6810fc91 3290 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
514f1c67
ACM
3291 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3292 "trace events on existing process id"),
ac9be8ee 3293 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
514f1c67 3294 "trace events on existing thread id"),
fa0e4ffe
ACM
3295 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3296 "pids to filter (by the kernel)", trace__set_filter_pids),
ac9be8ee 3297 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
514f1c67 3298 "system-wide collection from all CPUs"),
ac9be8ee 3299 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
514f1c67 3300 "list of cpus to monitor"),
6810fc91 3301 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
514f1c67 3302 "child tasks do not inherit counters"),
994a1f78
JO
3303 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3304 "number of mmap data pages",
3305 perf_evlist__parse_mmap_pages),
ac9be8ee 3306 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
514f1c67 3307 "user to profile"),
ae9ed035
ACM
3308 OPT_CALLBACK(0, "duration", &trace, "float",
3309 "show only events with duration > N.M ms",
3310 trace__set_duration),
1302d88e 3311 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
7c304ee0 3312 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
4bb09192
DA
3313 OPT_BOOLEAN('T', "time", &trace.full_time,
3314 "Show full timestamp, not time relative to first start"),
fd2eabaf
DA
3315 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3316 "Show only syscall summary with statistics"),
3317 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3318 "Show all syscalls and summary with statistics"),
598d02c5
SF
3319 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3320 "Trace pagefaults", parse_pagefaults, "maj"),
e281a960 3321 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
e366a6d8 3322 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
566a0885
MW
3323 OPT_CALLBACK(0, "call-graph", &trace.opts,
3324 "record_mode[,record_size]", record_callchain_help,
3325 &record_parse_callchain_opt),
44621819
ACM
3326 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3327 "Show the kernel callchains on the syscall exit path"),
9d9cad76
KL
3328 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3329 "per thread proc mmap processing timeout in ms"),
514f1c67
ACM
3330 OPT_END()
3331 };
6fdd9cb7 3332 const char * const trace_subcommands[] = { "record", NULL };
514f1c67 3333 int err;
32caf0d1 3334 char bf[BUFSIZ];
514f1c67 3335
4d08cb80
ACM
3336 signal(SIGSEGV, sighandler_dump_stack);
3337 signal(SIGFPE, sighandler_dump_stack);
3338
14a052df 3339 trace.evlist = perf_evlist__new();
fd0db102 3340 trace.sctbl = syscalltbl__new();
14a052df 3341
fd0db102 3342 if (trace.evlist == NULL || trace.sctbl == NULL) {
14a052df 3343 pr_err("Not enough memory to run!\n");
ff8f695c 3344 err = -ENOMEM;
14a052df
ACM
3345 goto out;
3346 }
3347
6fdd9cb7
YS
3348 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3349 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
fd2eabaf 3350
d7888573
WN
3351 err = bpf__setup_stdout(trace.evlist);
3352 if (err) {
3353 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3354 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3355 goto out;
3356 }
3357
59247e33
ACM
3358 err = -1;
3359
598d02c5
SF
3360 if (trace.trace_pgfaults) {
3361 trace.opts.sample_address = true;
3362 trace.opts.sample_time = true;
3363 }
3364
566a0885
MW
3365 if (trace.opts.callgraph_set)
3366 symbol_conf.use_callchain = true;
3367
14a052df
ACM
3368 if (trace.evlist->nr_entries > 0)
3369 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3370
1e28fe0a
SF
3371 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3372 return trace__record(&trace, argc-1, &argv[1]);
3373
3374 /* summary_only implies summary option, but don't overwrite summary if set */
3375 if (trace.summary_only)
3376 trace.summary = trace.summary_only;
3377
726f3234
ACM
3378 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3379 trace.evlist->nr_entries == 0 /* Was --events used? */) {
e281a960
SF
3380 pr_err("Please specify something to trace.\n");
3381 return -1;
3382 }
3383
59247e33
ACM
3384 if (!trace.trace_syscalls && ev_qualifier_str) {
3385 pr_err("The -e option can't be used with --no-syscalls.\n");
3386 goto out;
3387 }
3388
c24ff998
ACM
3389 if (output_name != NULL) {
3390 err = trace__open_output(&trace, output_name);
3391 if (err < 0) {
3392 perror("failed to create output file");
3393 goto out;
3394 }
3395 }
3396
fd0db102
ACM
3397 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3398
2ae3a312 3399 if (ev_qualifier_str != NULL) {
b059efdf 3400 const char *s = ev_qualifier_str;
005438a8
ACM
3401 struct strlist_config slist_config = {
3402 .dirname = system_path(STRACE_GROUPS_DIR),
3403 };
b059efdf
ACM
3404
3405 trace.not_ev_qualifier = *s == '!';
3406 if (trace.not_ev_qualifier)
3407 ++s;
005438a8 3408 trace.ev_qualifier = strlist__new(s, &slist_config);
2ae3a312 3409 if (trace.ev_qualifier == NULL) {
c24ff998
ACM
3410 fputs("Not enough memory to parse event qualifier",
3411 trace.output);
3412 err = -ENOMEM;
3413 goto out_close;
2ae3a312 3414 }
d0cc439b
ACM
3415
3416 err = trace__validate_ev_qualifier(&trace);
3417 if (err)
3418 goto out_close;
2ae3a312
ACM
3419 }
3420
602ad878 3421 err = target__validate(&trace.opts.target);
32caf0d1 3422 if (err) {
602ad878 3423 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
3424 fprintf(trace.output, "%s", bf);
3425 goto out_close;
32caf0d1
NK
3426 }
3427
602ad878 3428 err = target__parse_uid(&trace.opts.target);
514f1c67 3429 if (err) {
602ad878 3430 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
3431 fprintf(trace.output, "%s", bf);
3432 goto out_close;
514f1c67
ACM
3433 }
3434
602ad878 3435 if (!argc && target__none(&trace.opts.target))
ee76120e
NK
3436 trace.opts.target.system_wide = true;
3437
6810fc91
DA
3438 if (input_name)
3439 err = trace__replay(&trace);
3440 else
3441 err = trace__run(&trace, argc, argv);
1302d88e 3442
c24ff998
ACM
3443out_close:
3444 if (output_name != NULL)
3445 fclose(trace.output);
3446out:
1302d88e 3447 return err;
514f1c67 3448}