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