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