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