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