perf trace: Beautify set_tid_address, getpid, getppid return values
[linux-2.6-block.git] / tools / perf / builtin-trace.c
CommitLineData
a598bb5e
ACM
1/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
4e319027 19#include <traceevent/event-parse.h>
988bdb31 20#include <api/fs/tracing_path.h>
514f1c67 21#include "builtin.h"
752fde44 22#include "util/color.h"
7c304ee0 23#include "util/debug.h"
514f1c67 24#include "util/evlist.h"
4b6ab94e 25#include <subcmd/exec-cmd.h>
752fde44 26#include "util/machine.h"
6810fc91 27#include "util/session.h"
752fde44 28#include "util/thread.h"
4b6ab94e 29#include <subcmd/parse-options.h>
2ae3a312 30#include "util/strlist.h"
bdc89661 31#include "util/intlist.h"
514f1c67 32#include "util/thread_map.h"
bf2575c1 33#include "util/stat.h"
97978b3e 34#include "trace-event.h"
9aca7f17 35#include "util/parse-events.h"
ba504235 36#include "util/bpf-loader.h"
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), },
c65f1070
ACM
1169 { .name = "getpid", .errpid = true, },
1170 { .name = "getppid", .errpid = true, },
39878d49
ACM
1171 { .name = "getrandom", .errmsg = true,
1172 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
453350dd 1173 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
34221118
ACM
1174 { .name = "getxattr", .errmsg = true,
1175 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1176 { .name = "inotify_add_watch", .errmsg = true,
1177 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
beccb2b5 1178 { .name = "ioctl", .errmsg = true,
48000a1a 1179 .arg_scnprintf = { [0] = SCA_FD, /* fd */
844ae5b4
ACM
1180#if defined(__i386__) || defined(__x86_64__)
1181/*
1182 * FIXME: Make this available to all arches.
1183 */
78645cf3
ACM
1184 [1] = SCA_STRHEXARRAY, /* cmd */
1185 [2] = SCA_HEX, /* arg */ },
1186 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
844ae5b4
ACM
1187#else
1188 [2] = SCA_HEX, /* arg */ }, },
1189#endif
b62bee1b 1190 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
8bad5b0a
ACM
1191 { .name = "kill", .errmsg = true,
1192 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
34221118
ACM
1193 { .name = "lchown", .errmsg = true,
1194 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1195 { .name = "lgetxattr", .errmsg = true,
1196 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
75b757ca 1197 { .name = "linkat", .errmsg = true,
48000a1a 1198 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
34221118
ACM
1199 { .name = "listxattr", .errmsg = true,
1200 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
090389b6
ACM
1201 { .name = "llistxattr", .errmsg = true,
1202 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1203 { .name = "lremovexattr", .errmsg = true,
1204 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
75b757ca
ACM
1205 { .name = "lseek", .errmsg = true,
1206 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1207 [2] = SCA_STRARRAY, /* whence */ },
1208 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
34221118
ACM
1209 { .name = "lsetxattr", .errmsg = true,
1210 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
090389b6
ACM
1211 { .name = "lstat", .errmsg = true, .alias = "newlstat",
1212 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
34221118
ACM
1213 { .name = "lsxattr", .errmsg = true,
1214 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
9e9716d1
ACM
1215 { .name = "madvise", .errmsg = true,
1216 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1217 [2] = SCA_MADV_BHV, /* behavior */ }, },
34221118
ACM
1218 { .name = "mkdir", .errmsg = true,
1219 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
75b757ca 1220 { .name = "mkdirat", .errmsg = true,
34221118
ACM
1221 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1222 [1] = SCA_FILENAME, /* pathname */ }, },
1223 { .name = "mknod", .errmsg = true,
1224 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
75b757ca 1225 { .name = "mknodat", .errmsg = true,
090389b6
ACM
1226 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1227 [1] = SCA_FILENAME, /* filename */ }, },
3d903aa7
ACM
1228 { .name = "mlock", .errmsg = true,
1229 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1230 { .name = "mlockall", .errmsg = true,
1231 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
beccb2b5 1232 { .name = "mmap", .hexret = true,
ae685380 1233 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
941557e0 1234 [2] = SCA_MMAP_PROT, /* prot */
73faab3a
NK
1235 [3] = SCA_MMAP_FLAGS, /* flags */
1236 [4] = SCA_FD, /* fd */ }, },
beccb2b5 1237 { .name = "mprotect", .errmsg = true,
ae685380
ACM
1238 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1239 [2] = SCA_MMAP_PROT, /* prot */ }, },
090389b6
ACM
1240 { .name = "mq_unlink", .errmsg = true,
1241 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
ae685380
ACM
1242 { .name = "mremap", .hexret = true,
1243 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
86998dda 1244 [3] = SCA_MREMAP_FLAGS, /* flags */
ae685380 1245 [4] = SCA_HEX, /* new_addr */ }, },
3d903aa7
ACM
1246 { .name = "munlock", .errmsg = true,
1247 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
beccb2b5
ACM
1248 { .name = "munmap", .errmsg = true,
1249 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
75b757ca 1250 { .name = "name_to_handle_at", .errmsg = true,
48000a1a 1251 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
75b757ca 1252 { .name = "newfstatat", .errmsg = true,
34221118
ACM
1253 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1254 [1] = SCA_FILENAME, /* filename */ }, },
be65a89a 1255 { .name = "open", .errmsg = true,
f994592d
ACM
1256 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1257 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
31cd3855 1258 { .name = "open_by_handle_at", .errmsg = true,
75b757ca
ACM
1259 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1260 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
31cd3855 1261 { .name = "openat", .errmsg = true,
75b757ca 1262 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
34221118 1263 [1] = SCA_FILENAME, /* filename */
75b757ca 1264 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
a1c2552d
ACM
1265 { .name = "perf_event_open", .errmsg = true,
1266 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1267 [2] = SCA_INT, /* cpu */
1268 [3] = SCA_FD, /* group_fd */
1269 [4] = SCA_PERF_FLAGS, /* flags */ }, },
46cce19b
ACM
1270 { .name = "pipe2", .errmsg = true,
1271 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
aec1930b
ACM
1272 { .name = "poll", .errmsg = true, .timeout = true, },
1273 { .name = "ppoll", .errmsg = true, .timeout = true, },
75b757ca 1274 { .name = "pread", .errmsg = true, .alias = "pread64",
48000a1a 1275 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1276 { .name = "preadv", .errmsg = true, .alias = "pread",
48000a1a 1277 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
453350dd 1278 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
75b757ca 1279 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
48000a1a 1280 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1281 { .name = "pwritev", .errmsg = true,
48000a1a 1282 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1283 { .name = "read", .errmsg = true,
48000a1a 1284 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
34221118
ACM
1285 { .name = "readlink", .errmsg = true,
1286 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
75b757ca 1287 { .name = "readlinkat", .errmsg = true,
34221118
ACM
1288 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1289 [1] = SCA_FILENAME, /* pathname */ }, },
75b757ca 1290 { .name = "readv", .errmsg = true,
48000a1a 1291 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
b2cc99fd 1292 { .name = "recvfrom", .errmsg = true,
8d8c66a2
ACM
1293 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1294 [3] = SCA_MSG_FLAGS, /* flags */ }, },
b2cc99fd 1295 { .name = "recvmmsg", .errmsg = true,
8d8c66a2
ACM
1296 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1297 [3] = SCA_MSG_FLAGS, /* flags */ }, },
b2cc99fd 1298 { .name = "recvmsg", .errmsg = true,
8d8c66a2
ACM
1299 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1300 [2] = SCA_MSG_FLAGS, /* flags */ }, },
34221118
ACM
1301 { .name = "removexattr", .errmsg = true,
1302 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
75b757ca 1303 { .name = "renameat", .errmsg = true,
48000a1a 1304 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
34221118
ACM
1305 { .name = "rmdir", .errmsg = true,
1306 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
8bad5b0a
ACM
1307 { .name = "rt_sigaction", .errmsg = true,
1308 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
453350dd 1309 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
8bad5b0a
ACM
1310 { .name = "rt_sigqueueinfo", .errmsg = true,
1311 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1312 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1313 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
a3bca91f
ACM
1314 { .name = "sched_setscheduler", .errmsg = true,
1315 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
997bba8c
ACM
1316 { .name = "seccomp", .errmsg = true,
1317 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
1318 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
aec1930b 1319 { .name = "select", .errmsg = true, .timeout = true, },
b2cc99fd 1320 { .name = "sendmmsg", .errmsg = true,
8d8c66a2
ACM
1321 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1322 [3] = SCA_MSG_FLAGS, /* flags */ }, },
b2cc99fd 1323 { .name = "sendmsg", .errmsg = true,
8d8c66a2
ACM
1324 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1325 [2] = SCA_MSG_FLAGS, /* flags */ }, },
b2cc99fd 1326 { .name = "sendto", .errmsg = true,
8d8c66a2
ACM
1327 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1328 [3] = SCA_MSG_FLAGS, /* flags */ }, },
c65f1070 1329 { .name = "set_tid_address", .errpid = true, },
453350dd
ACM
1330 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1331 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
34221118
ACM
1332 { .name = "setxattr", .errmsg = true,
1333 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
75b757ca 1334 { .name = "shutdown", .errmsg = true,
48000a1a 1335 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
e10bce81 1336 { .name = "socket", .errmsg = true,
a28b24b2
ACM
1337 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1338 [1] = SCA_SK_TYPE, /* type */ },
07120aa5
ACM
1339 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
1340 { .name = "socketpair", .errmsg = true,
1341 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1342 [1] = SCA_SK_TYPE, /* type */ },
e10bce81 1343 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
090389b6
ACM
1344 { .name = "stat", .errmsg = true, .alias = "newstat",
1345 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
34221118
ACM
1346 { .name = "statfs", .errmsg = true,
1347 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1348 { .name = "swapoff", .errmsg = true,
1349 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1350 { .name = "swapon", .errmsg = true,
1351 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
75b757ca 1352 { .name = "symlinkat", .errmsg = true,
48000a1a 1353 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
8bad5b0a
ACM
1354 { .name = "tgkill", .errmsg = true,
1355 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1356 { .name = "tkill", .errmsg = true,
1357 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
34221118
ACM
1358 { .name = "truncate", .errmsg = true,
1359 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
e5959683 1360 { .name = "uname", .errmsg = true, .alias = "newuname", },
75b757ca 1361 { .name = "unlinkat", .errmsg = true,
34221118
ACM
1362 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1363 [1] = SCA_FILENAME, /* pathname */ }, },
1364 { .name = "utime", .errmsg = true,
1365 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
75b757ca 1366 { .name = "utimensat", .errmsg = true,
34221118
ACM
1367 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1368 [1] = SCA_FILENAME, /* filename */ }, },
1369 { .name = "utimes", .errmsg = true,
1370 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
090389b6
ACM
1371 { .name = "vmsplice", .errmsg = true,
1372 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
11c8e39f 1373 { .name = "wait4", .errpid = true,
7206b900 1374 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
11c8e39f 1375 { .name = "waitid", .errpid = true,
7206b900 1376 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
75b757ca 1377 { .name = "write", .errmsg = true,
48000a1a 1378 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1379 { .name = "writev", .errmsg = true,
48000a1a 1380 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
514f1c67
ACM
1381};
1382
1383static int syscall_fmt__cmp(const void *name, const void *fmtp)
1384{
1385 const struct syscall_fmt *fmt = fmtp;
1386 return strcmp(name, fmt->name);
1387}
1388
1389static struct syscall_fmt *syscall_fmt__find(const char *name)
1390{
1391 const int nmemb = ARRAY_SIZE(syscall_fmts);
1392 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1393}
1394
1395struct syscall {
1396 struct event_format *tp_format;
f208bd8d
ACM
1397 int nr_args;
1398 struct format_field *args;
514f1c67 1399 const char *name;
5089f20e 1400 bool is_exit;
514f1c67 1401 struct syscall_fmt *fmt;
01533e97 1402 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
1f115cb7 1403 void **arg_parm;
514f1c67
ACM
1404};
1405
60c907ab
ACM
1406static size_t fprintf_duration(unsigned long t, FILE *fp)
1407{
1408 double duration = (double)t / NSEC_PER_MSEC;
1409 size_t printed = fprintf(fp, "(");
1410
1411 if (duration >= 1.0)
1412 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1413 else if (duration >= 0.01)
1414 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1415 else
1416 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
c24ff998 1417 return printed + fprintf(fp, "): ");
60c907ab
ACM
1418}
1419
f994592d
ACM
1420/**
1421 * filename.ptr: The filename char pointer that will be vfs_getname'd
1422 * filename.entry_str_pos: Where to insert the string translated from
1423 * filename.ptr by the vfs_getname tracepoint/kprobe.
1424 */
752fde44
ACM
1425struct thread_trace {
1426 u64 entry_time;
1427 u64 exit_time;
1428 bool entry_pending;
efd5745e 1429 unsigned long nr_events;
a2ea67d7 1430 unsigned long pfmaj, pfmin;
752fde44 1431 char *entry_str;
1302d88e 1432 double runtime_ms;
f994592d
ACM
1433 struct {
1434 unsigned long ptr;
7f4f8001
ACM
1435 short int entry_str_pos;
1436 bool pending_open;
1437 unsigned int namelen;
1438 char *name;
f994592d 1439 } filename;
75b757ca
ACM
1440 struct {
1441 int max;
1442 char **table;
1443 } paths;
bf2575c1
DA
1444
1445 struct intlist *syscall_stats;
752fde44
ACM
1446};
1447
1448static struct thread_trace *thread_trace__new(void)
1449{
75b757ca
ACM
1450 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1451
1452 if (ttrace)
1453 ttrace->paths.max = -1;
1454
bf2575c1
DA
1455 ttrace->syscall_stats = intlist__new(NULL);
1456
75b757ca 1457 return ttrace;
752fde44
ACM
1458}
1459
c24ff998 1460static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
752fde44 1461{
efd5745e
ACM
1462 struct thread_trace *ttrace;
1463
752fde44
ACM
1464 if (thread == NULL)
1465 goto fail;
1466
89dceb22
NK
1467 if (thread__priv(thread) == NULL)
1468 thread__set_priv(thread, thread_trace__new());
48000a1a 1469
89dceb22 1470 if (thread__priv(thread) == NULL)
752fde44
ACM
1471 goto fail;
1472
89dceb22 1473 ttrace = thread__priv(thread);
efd5745e
ACM
1474 ++ttrace->nr_events;
1475
1476 return ttrace;
752fde44 1477fail:
c24ff998 1478 color_fprintf(fp, PERF_COLOR_RED,
752fde44
ACM
1479 "WARNING: not enough memory, dropping samples!\n");
1480 return NULL;
1481}
1482
598d02c5
SF
1483#define TRACE_PFMAJ (1 << 0)
1484#define TRACE_PFMIN (1 << 1)
1485
e4d44e83
ACM
1486static const size_t trace__entry_str_size = 2048;
1487
514f1c67 1488struct trace {
c24ff998 1489 struct perf_tool tool;
c522739d
ACM
1490 struct {
1491 int machine;
1492 int open_id;
1493 } audit;
514f1c67
ACM
1494 struct {
1495 int max;
1496 struct syscall *table;
c27366f0 1497 struct {
8b3ce757
ACM
1498 struct perf_evsel *sys_enter,
1499 *sys_exit;
c27366f0 1500 } events;
514f1c67 1501 } syscalls;
b4006796 1502 struct record_opts opts;
14a052df 1503 struct perf_evlist *evlist;
8fb598e5 1504 struct machine *host;
e596663e 1505 struct thread *current;
752fde44 1506 u64 base_time;
c24ff998 1507 FILE *output;
efd5745e 1508 unsigned long nr_events;
b059efdf 1509 struct strlist *ev_qualifier;
8b3ce757
ACM
1510 struct {
1511 size_t nr;
1512 int *entries;
1513 } ev_qualifier_ids;
bdc89661
DA
1514 struct intlist *tid_list;
1515 struct intlist *pid_list;
f078c385
ACM
1516 struct {
1517 size_t nr;
1518 pid_t *entries;
1519 } filter_pids;
98eafce6
ACM
1520 double duration_filter;
1521 double runtime_ms;
1522 struct {
1523 u64 vfs_getname,
1524 proc_getname;
1525 } stats;
1526 bool not_ev_qualifier;
1527 bool live;
1528 bool full_time;
1302d88e 1529 bool sched;
752fde44 1530 bool multiple_threads;
bf2575c1 1531 bool summary;
fd2eabaf 1532 bool summary_only;
50c95cbd 1533 bool show_comm;
c522739d 1534 bool show_tool_stats;
e281a960 1535 bool trace_syscalls;
e366a6d8 1536 bool force;
08c98776 1537 bool vfs_getname;
598d02c5 1538 int trace_pgfaults;
514f1c67
ACM
1539};
1540
97119f37 1541static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
75b757ca 1542{
89dceb22 1543 struct thread_trace *ttrace = thread__priv(thread);
75b757ca
ACM
1544
1545 if (fd > ttrace->paths.max) {
1546 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1547
1548 if (npath == NULL)
1549 return -1;
1550
1551 if (ttrace->paths.max != -1) {
1552 memset(npath + ttrace->paths.max + 1, 0,
1553 (fd - ttrace->paths.max) * sizeof(char *));
1554 } else {
1555 memset(npath, 0, (fd + 1) * sizeof(char *));
1556 }
1557
1558 ttrace->paths.table = npath;
1559 ttrace->paths.max = fd;
1560 }
1561
1562 ttrace->paths.table[fd] = strdup(pathname);
1563
1564 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1565}
1566
97119f37
ACM
1567static int thread__read_fd_path(struct thread *thread, int fd)
1568{
1569 char linkname[PATH_MAX], pathname[PATH_MAX];
1570 struct stat st;
1571 int ret;
1572
1573 if (thread->pid_ == thread->tid) {
1574 scnprintf(linkname, sizeof(linkname),
1575 "/proc/%d/fd/%d", thread->pid_, fd);
1576 } else {
1577 scnprintf(linkname, sizeof(linkname),
1578 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1579 }
1580
1581 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1582 return -1;
1583
1584 ret = readlink(linkname, pathname, sizeof(pathname));
1585
1586 if (ret < 0 || ret > st.st_size)
1587 return -1;
1588
1589 pathname[ret] = '\0';
1590 return trace__set_fd_pathname(thread, fd, pathname);
1591}
1592
c522739d
ACM
1593static const char *thread__fd_path(struct thread *thread, int fd,
1594 struct trace *trace)
75b757ca 1595{
89dceb22 1596 struct thread_trace *ttrace = thread__priv(thread);
75b757ca
ACM
1597
1598 if (ttrace == NULL)
1599 return NULL;
1600
1601 if (fd < 0)
1602 return NULL;
1603
cdcd1e6b 1604 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
c522739d
ACM
1605 if (!trace->live)
1606 return NULL;
1607 ++trace->stats.proc_getname;
cdcd1e6b 1608 if (thread__read_fd_path(thread, fd))
c522739d
ACM
1609 return NULL;
1610 }
75b757ca
ACM
1611
1612 return ttrace->paths.table[fd];
1613}
1614
1615static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1616 struct syscall_arg *arg)
1617{
1618 int fd = arg->val;
1619 size_t printed = scnprintf(bf, size, "%d", fd);
c522739d 1620 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
75b757ca
ACM
1621
1622 if (path)
1623 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1624
1625 return printed;
1626}
1627
1628static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1629 struct syscall_arg *arg)
1630{
1631 int fd = arg->val;
1632 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
89dceb22 1633 struct thread_trace *ttrace = thread__priv(arg->thread);
75b757ca 1634
04662523
ACM
1635 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1636 zfree(&ttrace->paths.table[fd]);
75b757ca
ACM
1637
1638 return printed;
1639}
1640
f994592d
ACM
1641static void thread__set_filename_pos(struct thread *thread, const char *bf,
1642 unsigned long ptr)
1643{
1644 struct thread_trace *ttrace = thread__priv(thread);
1645
1646 ttrace->filename.ptr = ptr;
1647 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1648}
1649
1650static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1651 struct syscall_arg *arg)
1652{
1653 unsigned long ptr = arg->val;
1654
1655 if (!arg->trace->vfs_getname)
1656 return scnprintf(bf, size, "%#x", ptr);
1657
1658 thread__set_filename_pos(arg->thread, bf, ptr);
1659 return 0;
1660}
1661
ae9ed035
ACM
1662static bool trace__filter_duration(struct trace *trace, double t)
1663{
1664 return t < (trace->duration_filter * NSEC_PER_MSEC);
1665}
1666
752fde44
ACM
1667static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1668{
1669 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1670
60c907ab 1671 return fprintf(fp, "%10.3f ", ts);
752fde44
ACM
1672}
1673
f15eb531 1674static bool done = false;
ba209f85 1675static bool interrupted = false;
f15eb531 1676
ba209f85 1677static void sig_handler(int sig)
f15eb531
NK
1678{
1679 done = true;
ba209f85 1680 interrupted = sig == SIGINT;
f15eb531
NK
1681}
1682
752fde44 1683static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
60c907ab 1684 u64 duration, u64 tstamp, FILE *fp)
752fde44
ACM
1685{
1686 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
60c907ab 1687 printed += fprintf_duration(duration, fp);
752fde44 1688
50c95cbd
ACM
1689 if (trace->multiple_threads) {
1690 if (trace->show_comm)
1902efe7 1691 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
38051234 1692 printed += fprintf(fp, "%d ", thread->tid);
50c95cbd 1693 }
752fde44
ACM
1694
1695 return printed;
1696}
1697
c24ff998 1698static int trace__process_event(struct trace *trace, struct machine *machine,
162f0bef 1699 union perf_event *event, struct perf_sample *sample)
752fde44
ACM
1700{
1701 int ret = 0;
1702
1703 switch (event->header.type) {
1704 case PERF_RECORD_LOST:
c24ff998 1705 color_fprintf(trace->output, PERF_COLOR_RED,
752fde44 1706 "LOST %" PRIu64 " events!\n", event->lost.lost);
162f0bef 1707 ret = machine__process_lost_event(machine, event, sample);
3ed5ca2e 1708 break;
752fde44 1709 default:
162f0bef 1710 ret = machine__process_event(machine, event, sample);
752fde44
ACM
1711 break;
1712 }
1713
1714 return ret;
1715}
1716
c24ff998 1717static int trace__tool_process(struct perf_tool *tool,
752fde44 1718 union perf_event *event,
162f0bef 1719 struct perf_sample *sample,
752fde44
ACM
1720 struct machine *machine)
1721{
c24ff998 1722 struct trace *trace = container_of(tool, struct trace, tool);
162f0bef 1723 return trace__process_event(trace, machine, event, sample);
752fde44
ACM
1724}
1725
1726static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1727{
0a7e6d1b 1728 int err = symbol__init(NULL);
752fde44
ACM
1729
1730 if (err)
1731 return err;
1732
8fb598e5
DA
1733 trace->host = machine__new_host();
1734 if (trace->host == NULL)
1735 return -ENOMEM;
752fde44 1736
959c2199 1737 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
706c3da4
ACM
1738 return -errno;
1739
a33fbd56 1740 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
9d9cad76
KL
1741 evlist->threads, trace__tool_process, false,
1742 trace->opts.proc_map_timeout);
752fde44
ACM
1743 if (err)
1744 symbol__exit();
1745
1746 return err;
1747}
1748
13d4ff3e
ACM
1749static int syscall__set_arg_fmts(struct syscall *sc)
1750{
1751 struct format_field *field;
1752 int idx = 0;
1753
f208bd8d 1754 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
13d4ff3e
ACM
1755 if (sc->arg_scnprintf == NULL)
1756 return -1;
1757
1f115cb7
ACM
1758 if (sc->fmt)
1759 sc->arg_parm = sc->fmt->arg_parm;
1760
f208bd8d 1761 for (field = sc->args; field; field = field->next) {
beccb2b5
ACM
1762 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1763 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1764 else if (field->flags & FIELD_IS_POINTER)
13d4ff3e
ACM
1765 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1766 ++idx;
1767 }
1768
1769 return 0;
1770}
1771
514f1c67
ACM
1772static int trace__read_syscall_info(struct trace *trace, int id)
1773{
1774 char tp_name[128];
1775 struct syscall *sc;
c522739d 1776 const char *name = audit_syscall_to_name(id, trace->audit.machine);
3a531260
ACM
1777
1778 if (name == NULL)
1779 return -1;
514f1c67
ACM
1780
1781 if (id > trace->syscalls.max) {
1782 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1783
1784 if (nsyscalls == NULL)
1785 return -1;
1786
1787 if (trace->syscalls.max != -1) {
1788 memset(nsyscalls + trace->syscalls.max + 1, 0,
1789 (id - trace->syscalls.max) * sizeof(*sc));
1790 } else {
1791 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1792 }
1793
1794 trace->syscalls.table = nsyscalls;
1795 trace->syscalls.max = id;
1796 }
1797
1798 sc = trace->syscalls.table + id;
3a531260 1799 sc->name = name;
2ae3a312 1800
3a531260 1801 sc->fmt = syscall_fmt__find(sc->name);
514f1c67 1802
aec1930b 1803 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
97978b3e 1804 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
aec1930b 1805
8dd2a131 1806 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
aec1930b 1807 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
97978b3e 1808 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
aec1930b 1809 }
514f1c67 1810
8dd2a131 1811 if (IS_ERR(sc->tp_format))
13d4ff3e
ACM
1812 return -1;
1813
f208bd8d
ACM
1814 sc->args = sc->tp_format->format.fields;
1815 sc->nr_args = sc->tp_format->format.nr_fields;
c42de706
TS
1816 /*
1817 * We need to check and discard the first variable '__syscall_nr'
1818 * or 'nr' that mean the syscall number. It is needless here.
1819 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1820 */
1821 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
f208bd8d
ACM
1822 sc->args = sc->args->next;
1823 --sc->nr_args;
1824 }
1825
5089f20e
ACM
1826 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1827
13d4ff3e 1828 return syscall__set_arg_fmts(sc);
514f1c67
ACM
1829}
1830
d0cc439b
ACM
1831static int trace__validate_ev_qualifier(struct trace *trace)
1832{
8b3ce757 1833 int err = 0, i;
d0cc439b
ACM
1834 struct str_node *pos;
1835
8b3ce757
ACM
1836 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1837 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1838 sizeof(trace->ev_qualifier_ids.entries[0]));
1839
1840 if (trace->ev_qualifier_ids.entries == NULL) {
1841 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1842 trace->output);
1843 err = -EINVAL;
1844 goto out;
1845 }
1846
1847 i = 0;
1848
d0cc439b
ACM
1849 strlist__for_each(pos, trace->ev_qualifier) {
1850 const char *sc = pos->s;
8b3ce757 1851 int id = audit_name_to_syscall(sc, trace->audit.machine);
d0cc439b 1852
8b3ce757 1853 if (id < 0) {
d0cc439b
ACM
1854 if (err == 0) {
1855 fputs("Error:\tInvalid syscall ", trace->output);
1856 err = -EINVAL;
1857 } else {
1858 fputs(", ", trace->output);
1859 }
1860
1861 fputs(sc, trace->output);
1862 }
8b3ce757
ACM
1863
1864 trace->ev_qualifier_ids.entries[i++] = id;
d0cc439b
ACM
1865 }
1866
1867 if (err < 0) {
1868 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1869 "\nHint:\tand: 'man syscalls'\n", trace->output);
8b3ce757
ACM
1870 zfree(&trace->ev_qualifier_ids.entries);
1871 trace->ev_qualifier_ids.nr = 0;
d0cc439b 1872 }
8b3ce757 1873out:
d0cc439b
ACM
1874 return err;
1875}
1876
55d43bca
DA
1877/*
1878 * args is to be interpreted as a series of longs but we need to handle
1879 * 8-byte unaligned accesses. args points to raw_data within the event
1880 * and raw_data is guaranteed to be 8-byte unaligned because it is
1881 * preceded by raw_size which is a u32. So we need to copy args to a temp
1882 * variable to read it. Most notably this avoids extended load instructions
1883 * on unaligned addresses
1884 */
1885
752fde44 1886static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
55d43bca 1887 unsigned char *args, struct trace *trace,
75b757ca 1888 struct thread *thread)
514f1c67 1889{
514f1c67 1890 size_t printed = 0;
55d43bca
DA
1891 unsigned char *p;
1892 unsigned long val;
514f1c67 1893
f208bd8d 1894 if (sc->args != NULL) {
514f1c67 1895 struct format_field *field;
01533e97
ACM
1896 u8 bit = 1;
1897 struct syscall_arg arg = {
75b757ca
ACM
1898 .idx = 0,
1899 .mask = 0,
1900 .trace = trace,
1901 .thread = thread,
01533e97 1902 };
6e7eeb51 1903
f208bd8d 1904 for (field = sc->args; field;
01533e97
ACM
1905 field = field->next, ++arg.idx, bit <<= 1) {
1906 if (arg.mask & bit)
6e7eeb51 1907 continue;
55d43bca
DA
1908
1909 /* special care for unaligned accesses */
1910 p = args + sizeof(unsigned long) * arg.idx;
1911 memcpy(&val, p, sizeof(val));
1912
4aa58232
ACM
1913 /*
1914 * Suppress this argument if its value is zero and
1915 * and we don't have a string associated in an
1916 * strarray for it.
1917 */
55d43bca 1918 if (val == 0 &&
4aa58232
ACM
1919 !(sc->arg_scnprintf &&
1920 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1921 sc->arg_parm[arg.idx]))
22ae5cf1
ACM
1922 continue;
1923
752fde44 1924 printed += scnprintf(bf + printed, size - printed,
13d4ff3e 1925 "%s%s: ", printed ? ", " : "", field->name);
01533e97 1926 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
55d43bca 1927 arg.val = val;
1f115cb7
ACM
1928 if (sc->arg_parm)
1929 arg.parm = sc->arg_parm[arg.idx];
01533e97
ACM
1930 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1931 size - printed, &arg);
6e7eeb51 1932 } else {
13d4ff3e 1933 printed += scnprintf(bf + printed, size - printed,
55d43bca 1934 "%ld", val);
6e7eeb51 1935 }
514f1c67
ACM
1936 }
1937 } else {
01533e97
ACM
1938 int i = 0;
1939
514f1c67 1940 while (i < 6) {
55d43bca
DA
1941 /* special care for unaligned accesses */
1942 p = args + sizeof(unsigned long) * i;
1943 memcpy(&val, p, sizeof(val));
752fde44
ACM
1944 printed += scnprintf(bf + printed, size - printed,
1945 "%sarg%d: %ld",
55d43bca 1946 printed ? ", " : "", i, val);
514f1c67
ACM
1947 ++i;
1948 }
1949 }
1950
1951 return printed;
1952}
1953
ba3d7dee 1954typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 1955 union perf_event *event,
ba3d7dee
ACM
1956 struct perf_sample *sample);
1957
1958static struct syscall *trace__syscall_info(struct trace *trace,
bf2575c1 1959 struct perf_evsel *evsel, int id)
ba3d7dee 1960{
ba3d7dee
ACM
1961
1962 if (id < 0) {
adaa18bf
ACM
1963
1964 /*
1965 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1966 * before that, leaving at a higher verbosity level till that is
1967 * explained. Reproduced with plain ftrace with:
1968 *
1969 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1970 * grep "NR -1 " /t/trace_pipe
1971 *
1972 * After generating some load on the machine.
1973 */
1974 if (verbose > 1) {
1975 static u64 n;
1976 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1977 id, perf_evsel__name(evsel), ++n);
1978 }
ba3d7dee
ACM
1979 return NULL;
1980 }
1981
1982 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1983 trace__read_syscall_info(trace, id))
1984 goto out_cant_read;
1985
1986 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1987 goto out_cant_read;
1988
1989 return &trace->syscalls.table[id];
1990
1991out_cant_read:
7c304ee0
ACM
1992 if (verbose) {
1993 fprintf(trace->output, "Problems reading syscall %d", id);
1994 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1995 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1996 fputs(" information\n", trace->output);
1997 }
ba3d7dee
ACM
1998 return NULL;
1999}
2000
bf2575c1
DA
2001static void thread__update_stats(struct thread_trace *ttrace,
2002 int id, struct perf_sample *sample)
2003{
2004 struct int_node *inode;
2005 struct stats *stats;
2006 u64 duration = 0;
2007
2008 inode = intlist__findnew(ttrace->syscall_stats, id);
2009 if (inode == NULL)
2010 return;
2011
2012 stats = inode->priv;
2013 if (stats == NULL) {
2014 stats = malloc(sizeof(struct stats));
2015 if (stats == NULL)
2016 return;
2017 init_stats(stats);
2018 inode->priv = stats;
2019 }
2020
2021 if (ttrace->entry_time && sample->time > ttrace->entry_time)
2022 duration = sample->time - ttrace->entry_time;
2023
2024 update_stats(stats, duration);
2025}
2026
e596663e
ACM
2027static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
2028{
2029 struct thread_trace *ttrace;
2030 u64 duration;
2031 size_t printed;
2032
2033 if (trace->current == NULL)
2034 return 0;
2035
2036 ttrace = thread__priv(trace->current);
2037
2038 if (!ttrace->entry_pending)
2039 return 0;
2040
2041 duration = sample->time - ttrace->entry_time;
2042
2043 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
2044 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
2045 ttrace->entry_pending = false;
2046
2047 return printed;
2048}
2049
ba3d7dee 2050static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 2051 union perf_event *event __maybe_unused,
ba3d7dee
ACM
2052 struct perf_sample *sample)
2053{
752fde44 2054 char *msg;
ba3d7dee 2055 void *args;
752fde44 2056 size_t printed = 0;
2ae3a312 2057 struct thread *thread;
b91fc39f 2058 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
bf2575c1 2059 struct syscall *sc = trace__syscall_info(trace, evsel, id);
2ae3a312
ACM
2060 struct thread_trace *ttrace;
2061
2062 if (sc == NULL)
2063 return -1;
ba3d7dee 2064
8fb598e5 2065 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
c24ff998 2066 ttrace = thread__trace(thread, trace->output);
2ae3a312 2067 if (ttrace == NULL)
b91fc39f 2068 goto out_put;
ba3d7dee 2069
77170988 2070 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
752fde44
ACM
2071
2072 if (ttrace->entry_str == NULL) {
e4d44e83 2073 ttrace->entry_str = malloc(trace__entry_str_size);
752fde44 2074 if (!ttrace->entry_str)
b91fc39f 2075 goto out_put;
752fde44
ACM
2076 }
2077
13f22a2d 2078 if (!trace->summary_only)
6ebad5c1 2079 trace__printf_interrupted_entry(trace, sample);
e596663e 2080
752fde44
ACM
2081 ttrace->entry_time = sample->time;
2082 msg = ttrace->entry_str;
e4d44e83 2083 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
752fde44 2084
e4d44e83 2085 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
75b757ca 2086 args, trace, thread);
752fde44 2087
5089f20e 2088 if (sc->is_exit) {
fd2eabaf 2089 if (!trace->duration_filter && !trace->summary_only) {
c24ff998
ACM
2090 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
2091 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
ae9ed035 2092 }
7f4f8001 2093 } else {
752fde44 2094 ttrace->entry_pending = true;
7f4f8001
ACM
2095 /* See trace__vfs_getname & trace__sys_exit */
2096 ttrace->filename.pending_open = false;
2097 }
ba3d7dee 2098
f3b623b8
ACM
2099 if (trace->current != thread) {
2100 thread__put(trace->current);
2101 trace->current = thread__get(thread);
2102 }
b91fc39f
ACM
2103 err = 0;
2104out_put:
2105 thread__put(thread);
2106 return err;
ba3d7dee
ACM
2107}
2108
2109static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 2110 union perf_event *event __maybe_unused,
ba3d7dee
ACM
2111 struct perf_sample *sample)
2112{
2c82c3ad 2113 long ret;
60c907ab 2114 u64 duration = 0;
2ae3a312 2115 struct thread *thread;
b91fc39f 2116 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
bf2575c1 2117 struct syscall *sc = trace__syscall_info(trace, evsel, id);
2ae3a312
ACM
2118 struct thread_trace *ttrace;
2119
2120 if (sc == NULL)
2121 return -1;
ba3d7dee 2122
8fb598e5 2123 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
c24ff998 2124 ttrace = thread__trace(thread, trace->output);
2ae3a312 2125 if (ttrace == NULL)
b91fc39f 2126 goto out_put;
ba3d7dee 2127
bf2575c1
DA
2128 if (trace->summary)
2129 thread__update_stats(ttrace, id, sample);
2130
77170988 2131 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
ba3d7dee 2132
7f4f8001
ACM
2133 if (id == trace->audit.open_id && ret >= 0 && ttrace->filename.pending_open) {
2134 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
2135 ttrace->filename.pending_open = false;
c522739d
ACM
2136 ++trace->stats.vfs_getname;
2137 }
2138
752fde44
ACM
2139 ttrace->exit_time = sample->time;
2140
ae9ed035 2141 if (ttrace->entry_time) {
60c907ab 2142 duration = sample->time - ttrace->entry_time;
ae9ed035
ACM
2143 if (trace__filter_duration(trace, duration))
2144 goto out;
2145 } else if (trace->duration_filter)
2146 goto out;
60c907ab 2147
fd2eabaf
DA
2148 if (trace->summary_only)
2149 goto out;
2150
c24ff998 2151 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
752fde44
ACM
2152
2153 if (ttrace->entry_pending) {
c24ff998 2154 fprintf(trace->output, "%-70s", ttrace->entry_str);
752fde44 2155 } else {
c24ff998
ACM
2156 fprintf(trace->output, " ... [");
2157 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
2158 fprintf(trace->output, "]: %s()", sc->name);
752fde44
ACM
2159 }
2160
da3c9a44
ACM
2161 if (sc->fmt == NULL) {
2162signed_print:
2c82c3ad 2163 fprintf(trace->output, ") = %ld", ret);
11c8e39f 2164 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
942a91ed 2165 char bf[STRERR_BUFSIZE];
ba3d7dee
ACM
2166 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
2167 *e = audit_errno_to_name(-ret);
2168
c24ff998 2169 fprintf(trace->output, ") = -1 %s %s", e, emsg);
da3c9a44 2170 } else if (ret == 0 && sc->fmt->timeout)
c24ff998 2171 fprintf(trace->output, ") = 0 Timeout");
04b34729 2172 else if (sc->fmt->hexret)
2c82c3ad 2173 fprintf(trace->output, ") = %#lx", ret);
11c8e39f
ACM
2174 else if (sc->fmt->errpid) {
2175 struct thread *child = machine__find_thread(trace->host, ret, ret);
2176
2177 if (child != NULL) {
2178 fprintf(trace->output, ") = %ld", ret);
2179 if (child->comm_set)
2180 fprintf(trace->output, " (%s)", thread__comm_str(child));
2181 thread__put(child);
2182 }
2183 } else
da3c9a44 2184 goto signed_print;
ba3d7dee 2185
c24ff998 2186 fputc('\n', trace->output);
ae9ed035 2187out:
752fde44 2188 ttrace->entry_pending = false;
b91fc39f
ACM
2189 err = 0;
2190out_put:
2191 thread__put(thread);
2192 return err;
ba3d7dee
ACM
2193}
2194
c522739d 2195static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 2196 union perf_event *event __maybe_unused,
c522739d
ACM
2197 struct perf_sample *sample)
2198{
f994592d
ACM
2199 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2200 struct thread_trace *ttrace;
2201 size_t filename_len, entry_str_len, to_move;
2202 ssize_t remaining_space;
2203 char *pos;
7f4f8001 2204 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
f994592d
ACM
2205
2206 if (!thread)
2207 goto out;
2208
2209 ttrace = thread__priv(thread);
2210 if (!ttrace)
2211 goto out;
2212
7f4f8001
ACM
2213 filename_len = strlen(filename);
2214
2215 if (ttrace->filename.namelen < filename_len) {
2216 char *f = realloc(ttrace->filename.name, filename_len + 1);
2217
2218 if (f == NULL)
2219 goto out;
2220
2221 ttrace->filename.namelen = filename_len;
2222 ttrace->filename.name = f;
2223 }
2224
2225 strcpy(ttrace->filename.name, filename);
2226 ttrace->filename.pending_open = true;
2227
f994592d
ACM
2228 if (!ttrace->filename.ptr)
2229 goto out;
2230
2231 entry_str_len = strlen(ttrace->entry_str);
2232 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2233 if (remaining_space <= 0)
2234 goto out;
2235
f994592d
ACM
2236 if (filename_len > (size_t)remaining_space) {
2237 filename += filename_len - remaining_space;
2238 filename_len = remaining_space;
2239 }
2240
2241 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2242 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2243 memmove(pos + filename_len, pos, to_move);
2244 memcpy(pos, filename, filename_len);
2245
2246 ttrace->filename.ptr = 0;
2247 ttrace->filename.entry_str_pos = 0;
2248out:
c522739d
ACM
2249 return 0;
2250}
2251
1302d88e 2252static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 2253 union perf_event *event __maybe_unused,
1302d88e
ACM
2254 struct perf_sample *sample)
2255{
2256 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2257 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
8fb598e5 2258 struct thread *thread = machine__findnew_thread(trace->host,
314add6b
AH
2259 sample->pid,
2260 sample->tid);
c24ff998 2261 struct thread_trace *ttrace = thread__trace(thread, trace->output);
1302d88e
ACM
2262
2263 if (ttrace == NULL)
2264 goto out_dump;
2265
2266 ttrace->runtime_ms += runtime_ms;
2267 trace->runtime_ms += runtime_ms;
b91fc39f 2268 thread__put(thread);
1302d88e
ACM
2269 return 0;
2270
2271out_dump:
c24ff998 2272 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
1302d88e
ACM
2273 evsel->name,
2274 perf_evsel__strval(evsel, sample, "comm"),
2275 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2276 runtime,
2277 perf_evsel__intval(evsel, sample, "vruntime"));
b91fc39f 2278 thread__put(thread);
1302d88e
ACM
2279 return 0;
2280}
2281
1d6c9407
WN
2282static void bpf_output__printer(enum binary_printer_ops op,
2283 unsigned int val, void *extra)
2284{
2285 FILE *output = extra;
2286 unsigned char ch = (unsigned char)val;
2287
2288 switch (op) {
2289 case BINARY_PRINT_CHAR_DATA:
2290 fprintf(output, "%c", isprint(ch) ? ch : '.');
2291 break;
2292 case BINARY_PRINT_DATA_BEGIN:
2293 case BINARY_PRINT_LINE_BEGIN:
2294 case BINARY_PRINT_ADDR:
2295 case BINARY_PRINT_NUM_DATA:
2296 case BINARY_PRINT_NUM_PAD:
2297 case BINARY_PRINT_SEP:
2298 case BINARY_PRINT_CHAR_PAD:
2299 case BINARY_PRINT_LINE_END:
2300 case BINARY_PRINT_DATA_END:
2301 default:
2302 break;
2303 }
2304}
2305
2306static void bpf_output__fprintf(struct trace *trace,
2307 struct perf_sample *sample)
2308{
2309 print_binary(sample->raw_data, sample->raw_size, 8,
2310 bpf_output__printer, trace->output);
2311}
2312
14a052df
ACM
2313static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2314 union perf_event *event __maybe_unused,
2315 struct perf_sample *sample)
2316{
2317 trace__printf_interrupted_entry(trace, sample);
2318 trace__fprintf_tstamp(trace, sample->time, trace->output);
0808921a
ACM
2319
2320 if (trace->trace_syscalls)
2321 fprintf(trace->output, "( ): ");
2322
2323 fprintf(trace->output, "%s:", evsel->name);
14a052df 2324
1d6c9407
WN
2325 if (perf_evsel__is_bpf_output(evsel)) {
2326 bpf_output__fprintf(trace, sample);
2327 } else if (evsel->tp_format) {
14a052df
ACM
2328 event_format__fprintf(evsel->tp_format, sample->cpu,
2329 sample->raw_data, sample->raw_size,
2330 trace->output);
2331 }
2332
2333 fprintf(trace->output, ")\n");
2334 return 0;
2335}
2336
598d02c5
SF
2337static void print_location(FILE *f, struct perf_sample *sample,
2338 struct addr_location *al,
2339 bool print_dso, bool print_sym)
2340{
2341
2342 if ((verbose || print_dso) && al->map)
2343 fprintf(f, "%s@", al->map->dso->long_name);
2344
2345 if ((verbose || print_sym) && al->sym)
4414a3c5 2346 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
598d02c5
SF
2347 al->addr - al->sym->start);
2348 else if (al->map)
4414a3c5 2349 fprintf(f, "0x%" PRIx64, al->addr);
598d02c5 2350 else
4414a3c5 2351 fprintf(f, "0x%" PRIx64, sample->addr);
598d02c5
SF
2352}
2353
2354static int trace__pgfault(struct trace *trace,
2355 struct perf_evsel *evsel,
473398a2 2356 union perf_event *event __maybe_unused,
598d02c5
SF
2357 struct perf_sample *sample)
2358{
2359 struct thread *thread;
598d02c5
SF
2360 struct addr_location al;
2361 char map_type = 'd';
a2ea67d7 2362 struct thread_trace *ttrace;
b91fc39f 2363 int err = -1;
598d02c5
SF
2364
2365 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
a2ea67d7
SF
2366 ttrace = thread__trace(thread, trace->output);
2367 if (ttrace == NULL)
b91fc39f 2368 goto out_put;
a2ea67d7
SF
2369
2370 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2371 ttrace->pfmaj++;
2372 else
2373 ttrace->pfmin++;
2374
2375 if (trace->summary_only)
b91fc39f 2376 goto out;
598d02c5 2377
473398a2 2378 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
598d02c5
SF
2379 sample->ip, &al);
2380
2381 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2382
2383 fprintf(trace->output, "%sfault [",
2384 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2385 "maj" : "min");
2386
2387 print_location(trace->output, sample, &al, false, true);
2388
2389 fprintf(trace->output, "] => ");
2390
473398a2 2391 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
598d02c5
SF
2392 sample->addr, &al);
2393
2394 if (!al.map) {
473398a2 2395 thread__find_addr_location(thread, sample->cpumode,
598d02c5
SF
2396 MAP__FUNCTION, sample->addr, &al);
2397
2398 if (al.map)
2399 map_type = 'x';
2400 else
2401 map_type = '?';
2402 }
2403
2404 print_location(trace->output, sample, &al, true, false);
2405
2406 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
b91fc39f
ACM
2407out:
2408 err = 0;
2409out_put:
2410 thread__put(thread);
2411 return err;
598d02c5
SF
2412}
2413
bdc89661
DA
2414static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2415{
2416 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2417 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2418 return false;
2419
2420 if (trace->pid_list || trace->tid_list)
2421 return true;
2422
2423 return false;
2424}
2425
e6001980 2426static void trace__set_base_time(struct trace *trace,
8a07a809 2427 struct perf_evsel *evsel,
e6001980
ACM
2428 struct perf_sample *sample)
2429{
8a07a809
ACM
2430 /*
2431 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2432 * and don't use sample->time unconditionally, we may end up having
2433 * some other event in the future without PERF_SAMPLE_TIME for good
2434 * reason, i.e. we may not be interested in its timestamps, just in
2435 * it taking place, picking some piece of information when it
2436 * appears in our event stream (vfs_getname comes to mind).
2437 */
2438 if (trace->base_time == 0 && !trace->full_time &&
2439 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
e6001980
ACM
2440 trace->base_time = sample->time;
2441}
2442
6810fc91 2443static int trace__process_sample(struct perf_tool *tool,
0c82adcf 2444 union perf_event *event,
6810fc91
DA
2445 struct perf_sample *sample,
2446 struct perf_evsel *evsel,
2447 struct machine *machine __maybe_unused)
2448{
2449 struct trace *trace = container_of(tool, struct trace, tool);
2450 int err = 0;
2451
744a9719 2452 tracepoint_handler handler = evsel->handler;
6810fc91 2453
bdc89661
DA
2454 if (skip_sample(trace, sample))
2455 return 0;
2456
e6001980 2457 trace__set_base_time(trace, evsel, sample);
6810fc91 2458
3160565f
DA
2459 if (handler) {
2460 ++trace->nr_events;
0c82adcf 2461 handler(trace, evsel, event, sample);
3160565f 2462 }
6810fc91
DA
2463
2464 return err;
2465}
2466
bdc89661
DA
2467static int parse_target_str(struct trace *trace)
2468{
2469 if (trace->opts.target.pid) {
2470 trace->pid_list = intlist__new(trace->opts.target.pid);
2471 if (trace->pid_list == NULL) {
2472 pr_err("Error parsing process id string\n");
2473 return -EINVAL;
2474 }
2475 }
2476
2477 if (trace->opts.target.tid) {
2478 trace->tid_list = intlist__new(trace->opts.target.tid);
2479 if (trace->tid_list == NULL) {
2480 pr_err("Error parsing thread id string\n");
2481 return -EINVAL;
2482 }
2483 }
2484
2485 return 0;
2486}
2487
1e28fe0a 2488static int trace__record(struct trace *trace, int argc, const char **argv)
5e2485b1
DA
2489{
2490 unsigned int rec_argc, i, j;
2491 const char **rec_argv;
2492 const char * const record_args[] = {
2493 "record",
2494 "-R",
2495 "-m", "1024",
2496 "-c", "1",
5e2485b1
DA
2497 };
2498
1e28fe0a
SF
2499 const char * const sc_args[] = { "-e", };
2500 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2501 const char * const majpf_args[] = { "-e", "major-faults" };
2502 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2503 const char * const minpf_args[] = { "-e", "minor-faults" };
2504 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2505
9aca7f17 2506 /* +1 is for the event string below */
1e28fe0a
SF
2507 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2508 majpf_args_nr + minpf_args_nr + argc;
5e2485b1
DA
2509 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2510
2511 if (rec_argv == NULL)
2512 return -ENOMEM;
2513
1e28fe0a 2514 j = 0;
5e2485b1 2515 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1e28fe0a
SF
2516 rec_argv[j++] = record_args[i];
2517
e281a960
SF
2518 if (trace->trace_syscalls) {
2519 for (i = 0; i < sc_args_nr; i++)
2520 rec_argv[j++] = sc_args[i];
2521
2522 /* event string may be different for older kernels - e.g., RHEL6 */
2523 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2524 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2525 else if (is_valid_tracepoint("syscalls:sys_enter"))
2526 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2527 else {
2528 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2529 return -1;
2530 }
9aca7f17 2531 }
9aca7f17 2532
1e28fe0a
SF
2533 if (trace->trace_pgfaults & TRACE_PFMAJ)
2534 for (i = 0; i < majpf_args_nr; i++)
2535 rec_argv[j++] = majpf_args[i];
2536
2537 if (trace->trace_pgfaults & TRACE_PFMIN)
2538 for (i = 0; i < minpf_args_nr; i++)
2539 rec_argv[j++] = minpf_args[i];
2540
2541 for (i = 0; i < (unsigned int)argc; i++)
2542 rec_argv[j++] = argv[i];
5e2485b1 2543
1e28fe0a 2544 return cmd_record(j, rec_argv, NULL);
5e2485b1
DA
2545}
2546
bf2575c1
DA
2547static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2548
08c98776 2549static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
c522739d 2550{
ef503831 2551 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
8dd2a131
JO
2552
2553 if (IS_ERR(evsel))
08c98776 2554 return false;
c522739d
ACM
2555
2556 if (perf_evsel__field(evsel, "pathname") == NULL) {
2557 perf_evsel__delete(evsel);
08c98776 2558 return false;
c522739d
ACM
2559 }
2560
744a9719 2561 evsel->handler = trace__vfs_getname;
c522739d 2562 perf_evlist__add(evlist, evsel);
08c98776 2563 return true;
c522739d
ACM
2564}
2565
598d02c5
SF
2566static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2567 u64 config)
2568{
2569 struct perf_evsel *evsel;
2570 struct perf_event_attr attr = {
2571 .type = PERF_TYPE_SOFTWARE,
2572 .mmap_data = 1,
598d02c5
SF
2573 };
2574
2575 attr.config = config;
0524798c 2576 attr.sample_period = 1;
598d02c5
SF
2577
2578 event_attr_init(&attr);
2579
2580 evsel = perf_evsel__new(&attr);
2581 if (!evsel)
2582 return -ENOMEM;
2583
2584 evsel->handler = trace__pgfault;
2585 perf_evlist__add(evlist, evsel);
2586
2587 return 0;
2588}
2589
ddbb1b13
ACM
2590static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2591{
2592 const u32 type = event->header.type;
2593 struct perf_evsel *evsel;
2594
ddbb1b13
ACM
2595 if (type != PERF_RECORD_SAMPLE) {
2596 trace__process_event(trace, trace->host, event, sample);
2597 return;
2598 }
2599
2600 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2601 if (evsel == NULL) {
2602 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2603 return;
2604 }
2605
e6001980
ACM
2606 trace__set_base_time(trace, evsel, sample);
2607
ddbb1b13
ACM
2608 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2609 sample->raw_data == NULL) {
2610 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2611 perf_evsel__name(evsel), sample->tid,
2612 sample->cpu, sample->raw_size);
2613 } else {
2614 tracepoint_handler handler = evsel->handler;
2615 handler(trace, evsel, event, sample);
2616 }
2617}
2618
c27366f0
ACM
2619static int trace__add_syscall_newtp(struct trace *trace)
2620{
2621 int ret = -1;
2622 struct perf_evlist *evlist = trace->evlist;
2623 struct perf_evsel *sys_enter, *sys_exit;
2624
2625 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2626 if (sys_enter == NULL)
2627 goto out;
2628
2629 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2630 goto out_delete_sys_enter;
2631
2632 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2633 if (sys_exit == NULL)
2634 goto out_delete_sys_enter;
2635
2636 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2637 goto out_delete_sys_exit;
2638
2639 perf_evlist__add(evlist, sys_enter);
2640 perf_evlist__add(evlist, sys_exit);
2641
8b3ce757
ACM
2642 trace->syscalls.events.sys_enter = sys_enter;
2643 trace->syscalls.events.sys_exit = sys_exit;
c27366f0
ACM
2644
2645 ret = 0;
2646out:
2647 return ret;
2648
2649out_delete_sys_exit:
2650 perf_evsel__delete_priv(sys_exit);
2651out_delete_sys_enter:
2652 perf_evsel__delete_priv(sys_enter);
2653 goto out;
2654}
2655
19867b61
ACM
2656static int trace__set_ev_qualifier_filter(struct trace *trace)
2657{
2658 int err = -1;
2659 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2660 trace->ev_qualifier_ids.nr,
2661 trace->ev_qualifier_ids.entries);
2662
2663 if (filter == NULL)
2664 goto out_enomem;
2665
2666 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2667 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2668
2669 free(filter);
2670out:
2671 return err;
2672out_enomem:
2673 errno = ENOMEM;
2674 goto out;
2675}
c27366f0 2676
f15eb531 2677static int trace__run(struct trace *trace, int argc, const char **argv)
514f1c67 2678{
14a052df 2679 struct perf_evlist *evlist = trace->evlist;
94ad89bc 2680 struct perf_evsel *evsel;
efd5745e
ACM
2681 int err = -1, i;
2682 unsigned long before;
f15eb531 2683 const bool forks = argc > 0;
46fb3c21 2684 bool draining = false;
514f1c67 2685
75b757ca
ACM
2686 trace->live = true;
2687
c27366f0 2688 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
801c67b0 2689 goto out_error_raw_syscalls;
514f1c67 2690
e281a960 2691 if (trace->trace_syscalls)
08c98776 2692 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
c522739d 2693
598d02c5 2694 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
e2726d99 2695 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
5ed08dae 2696 goto out_error_mem;
e2726d99 2697 }
598d02c5
SF
2698
2699 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2700 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
5ed08dae 2701 goto out_error_mem;
598d02c5 2702
1302d88e 2703 if (trace->sched &&
2cc990ba
ACM
2704 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2705 trace__sched_stat_runtime))
2706 goto out_error_sched_stat_runtime;
1302d88e 2707
514f1c67
ACM
2708 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2709 if (err < 0) {
c24ff998 2710 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
514f1c67
ACM
2711 goto out_delete_evlist;
2712 }
2713
752fde44
ACM
2714 err = trace__symbols_init(trace, evlist);
2715 if (err < 0) {
c24ff998 2716 fprintf(trace->output, "Problems initializing symbol libraries!\n");
03ad9747 2717 goto out_delete_evlist;
752fde44
ACM
2718 }
2719
f77a9518 2720 perf_evlist__config(evlist, &trace->opts);
514f1c67 2721
f15eb531
NK
2722 signal(SIGCHLD, sig_handler);
2723 signal(SIGINT, sig_handler);
2724
2725 if (forks) {
6ef73ec4 2726 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
735f7e0b 2727 argv, false, NULL);
f15eb531 2728 if (err < 0) {
c24ff998 2729 fprintf(trace->output, "Couldn't run the workload!\n");
03ad9747 2730 goto out_delete_evlist;
f15eb531
NK
2731 }
2732 }
2733
514f1c67 2734 err = perf_evlist__open(evlist);
a8f23d8f
ACM
2735 if (err < 0)
2736 goto out_error_open;
514f1c67 2737
ba504235
WN
2738 err = bpf__apply_obj_config();
2739 if (err) {
2740 char errbuf[BUFSIZ];
2741
2742 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2743 pr_err("ERROR: Apply config to BPF failed: %s\n",
2744 errbuf);
2745 goto out_error_open;
2746 }
2747
241b057c
ACM
2748 /*
2749 * Better not use !target__has_task() here because we need to cover the
2750 * case where no threads were specified in the command line, but a
2751 * workload was, and in that case we will fill in the thread_map when
2752 * we fork the workload in perf_evlist__prepare_workload.
2753 */
f078c385
ACM
2754 if (trace->filter_pids.nr > 0)
2755 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
e13798c7 2756 else if (thread_map__pid(evlist->threads, 0) == -1)
f078c385
ACM
2757 err = perf_evlist__set_filter_pid(evlist, getpid());
2758
94ad89bc
ACM
2759 if (err < 0)
2760 goto out_error_mem;
2761
19867b61
ACM
2762 if (trace->ev_qualifier_ids.nr > 0) {
2763 err = trace__set_ev_qualifier_filter(trace);
2764 if (err < 0)
2765 goto out_errno;
19867b61 2766
2e5e5f87
ACM
2767 pr_debug("event qualifier tracepoint filter: %s\n",
2768 trace->syscalls.events.sys_exit->filter);
2769 }
19867b61 2770
94ad89bc
ACM
2771 err = perf_evlist__apply_filters(evlist, &evsel);
2772 if (err < 0)
2773 goto out_error_apply_filters;
241b057c 2774
f885037e 2775 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
e09b18d4
ACM
2776 if (err < 0)
2777 goto out_error_mmap;
514f1c67 2778
cb24d01d
ACM
2779 if (!target__none(&trace->opts.target))
2780 perf_evlist__enable(evlist);
2781
f15eb531
NK
2782 if (forks)
2783 perf_evlist__start_workload(evlist);
2784
e13798c7 2785 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
42052bea
ACM
2786 evlist->threads->nr > 1 ||
2787 perf_evlist__first(evlist)->attr.inherit;
514f1c67 2788again:
efd5745e 2789 before = trace->nr_events;
514f1c67
ACM
2790
2791 for (i = 0; i < evlist->nr_mmaps; i++) {
2792 union perf_event *event;
2793
2794 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
514f1c67 2795 struct perf_sample sample;
514f1c67 2796
efd5745e 2797 ++trace->nr_events;
514f1c67 2798
514f1c67
ACM
2799 err = perf_evlist__parse_sample(evlist, event, &sample);
2800 if (err) {
c24ff998 2801 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
8e50d384 2802 goto next_event;
514f1c67
ACM
2803 }
2804
ddbb1b13 2805 trace__handle_event(trace, event, &sample);
8e50d384
ZZ
2806next_event:
2807 perf_evlist__mmap_consume(evlist, i);
20c5f10e 2808
ba209f85
ACM
2809 if (interrupted)
2810 goto out_disable;
02ac5421
ACM
2811
2812 if (done && !draining) {
2813 perf_evlist__disable(evlist);
2814 draining = true;
2815 }
514f1c67
ACM
2816 }
2817 }
2818
efd5745e 2819 if (trace->nr_events == before) {
ba209f85 2820 int timeout = done ? 100 : -1;
f15eb531 2821
46fb3c21
ACM
2822 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2823 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2824 draining = true;
2825
ba209f85 2826 goto again;
46fb3c21 2827 }
ba209f85
ACM
2828 } else {
2829 goto again;
f15eb531
NK
2830 }
2831
ba209f85 2832out_disable:
f3b623b8
ACM
2833 thread__zput(trace->current);
2834
ba209f85 2835 perf_evlist__disable(evlist);
514f1c67 2836
c522739d
ACM
2837 if (!err) {
2838 if (trace->summary)
2839 trace__fprintf_thread_summary(trace, trace->output);
2840
2841 if (trace->show_tool_stats) {
2842 fprintf(trace->output, "Stats:\n "
2843 " vfs_getname : %" PRIu64 "\n"
2844 " proc_getname: %" PRIu64 "\n",
2845 trace->stats.vfs_getname,
2846 trace->stats.proc_getname);
2847 }
2848 }
bf2575c1 2849
514f1c67
ACM
2850out_delete_evlist:
2851 perf_evlist__delete(evlist);
14a052df 2852 trace->evlist = NULL;
75b757ca 2853 trace->live = false;
514f1c67 2854 return err;
6ef068cb
ACM
2855{
2856 char errbuf[BUFSIZ];
a8f23d8f 2857
2cc990ba 2858out_error_sched_stat_runtime:
988bdb31 2859 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
2cc990ba
ACM
2860 goto out_error;
2861
801c67b0 2862out_error_raw_syscalls:
988bdb31 2863 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
a8f23d8f
ACM
2864 goto out_error;
2865
e09b18d4
ACM
2866out_error_mmap:
2867 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2868 goto out_error;
2869
a8f23d8f
ACM
2870out_error_open:
2871 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2872
2873out_error:
6ef068cb 2874 fprintf(trace->output, "%s\n", errbuf);
87f91868 2875 goto out_delete_evlist;
94ad89bc
ACM
2876
2877out_error_apply_filters:
2878 fprintf(trace->output,
2879 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2880 evsel->filter, perf_evsel__name(evsel), errno,
2881 strerror_r(errno, errbuf, sizeof(errbuf)));
2882 goto out_delete_evlist;
514f1c67 2883}
5ed08dae
ACM
2884out_error_mem:
2885 fprintf(trace->output, "Not enough memory to run!\n");
2886 goto out_delete_evlist;
19867b61
ACM
2887
2888out_errno:
2889 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2890 goto out_delete_evlist;
a8f23d8f 2891}
514f1c67 2892
6810fc91
DA
2893static int trace__replay(struct trace *trace)
2894{
2895 const struct perf_evsel_str_handler handlers[] = {
c522739d 2896 { "probe:vfs_getname", trace__vfs_getname, },
6810fc91 2897 };
f5fc1412
JO
2898 struct perf_data_file file = {
2899 .path = input_name,
2900 .mode = PERF_DATA_MODE_READ,
e366a6d8 2901 .force = trace->force,
f5fc1412 2902 };
6810fc91 2903 struct perf_session *session;
003824e8 2904 struct perf_evsel *evsel;
6810fc91
DA
2905 int err = -1;
2906
2907 trace->tool.sample = trace__process_sample;
2908 trace->tool.mmap = perf_event__process_mmap;
384c671e 2909 trace->tool.mmap2 = perf_event__process_mmap2;
6810fc91
DA
2910 trace->tool.comm = perf_event__process_comm;
2911 trace->tool.exit = perf_event__process_exit;
2912 trace->tool.fork = perf_event__process_fork;
2913 trace->tool.attr = perf_event__process_attr;
2914 trace->tool.tracing_data = perf_event__process_tracing_data;
2915 trace->tool.build_id = perf_event__process_build_id;
2916
0a8cb85c 2917 trace->tool.ordered_events = true;
6810fc91
DA
2918 trace->tool.ordering_requires_timestamps = true;
2919
2920 /* add tid to output */
2921 trace->multiple_threads = true;
2922
f5fc1412 2923 session = perf_session__new(&file, false, &trace->tool);
6810fc91 2924 if (session == NULL)
52e02834 2925 return -1;
6810fc91 2926
0a7e6d1b 2927 if (symbol__init(&session->header.env) < 0)
cb2ffae2
NK
2928 goto out;
2929
8fb598e5
DA
2930 trace->host = &session->machines.host;
2931
6810fc91
DA
2932 err = perf_session__set_tracepoints_handlers(session, handlers);
2933 if (err)
2934 goto out;
2935
003824e8
NK
2936 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2937 "raw_syscalls:sys_enter");
9aca7f17
DA
2938 /* older kernels have syscalls tp versus raw_syscalls */
2939 if (evsel == NULL)
2940 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2941 "syscalls:sys_enter");
003824e8 2942
e281a960
SF
2943 if (evsel &&
2944 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2945 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
003824e8
NK
2946 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2947 goto out;
2948 }
2949
2950 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2951 "raw_syscalls:sys_exit");
9aca7f17
DA
2952 if (evsel == NULL)
2953 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2954 "syscalls:sys_exit");
e281a960
SF
2955 if (evsel &&
2956 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2957 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
003824e8 2958 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
6810fc91
DA
2959 goto out;
2960 }
2961
1e28fe0a
SF
2962 evlist__for_each(session->evlist, evsel) {
2963 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2964 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2965 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2966 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2967 evsel->handler = trace__pgfault;
2968 }
2969
bdc89661
DA
2970 err = parse_target_str(trace);
2971 if (err != 0)
2972 goto out;
2973
6810fc91
DA
2974 setup_pager();
2975
b7b61cbe 2976 err = perf_session__process_events(session);
6810fc91
DA
2977 if (err)
2978 pr_err("Failed to process events, error %d", err);
2979
bf2575c1
DA
2980 else if (trace->summary)
2981 trace__fprintf_thread_summary(trace, trace->output);
2982
6810fc91
DA
2983out:
2984 perf_session__delete(session);
2985
2986 return err;
2987}
2988
1302d88e
ACM
2989static size_t trace__fprintf_threads_header(FILE *fp)
2990{
2991 size_t printed;
2992
99ff7150 2993 printed = fprintf(fp, "\n Summary of events:\n\n");
bf2575c1
DA
2994
2995 return printed;
2996}
2997
2998static size_t thread__dump_stats(struct thread_trace *ttrace,
2999 struct trace *trace, FILE *fp)
3000{
3001 struct stats *stats;
3002 size_t printed = 0;
3003 struct syscall *sc;
3004 struct int_node *inode = intlist__first(ttrace->syscall_stats);
3005
3006 if (inode == NULL)
3007 return 0;
3008
3009 printed += fprintf(fp, "\n");
3010
834fd46d
MW
3011 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
3012 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
3013 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
99ff7150 3014
bf2575c1
DA
3015 /* each int_node is a syscall */
3016 while (inode) {
3017 stats = inode->priv;
3018 if (stats) {
3019 double min = (double)(stats->min) / NSEC_PER_MSEC;
3020 double max = (double)(stats->max) / NSEC_PER_MSEC;
3021 double avg = avg_stats(stats);
3022 double pct;
3023 u64 n = (u64) stats->n;
3024
3025 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
3026 avg /= NSEC_PER_MSEC;
3027
3028 sc = &trace->syscalls.table[inode->i];
99ff7150 3029 printed += fprintf(fp, " %-15s", sc->name);
834fd46d
MW
3030 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
3031 n, avg * n, min, avg);
27a778b5 3032 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
bf2575c1
DA
3033 }
3034
3035 inode = intlist__next(inode);
3036 }
3037
3038 printed += fprintf(fp, "\n\n");
1302d88e
ACM
3039
3040 return printed;
3041}
3042
896cbb56
DA
3043/* struct used to pass data to per-thread function */
3044struct summary_data {
3045 FILE *fp;
3046 struct trace *trace;
3047 size_t printed;
3048};
3049
3050static int trace__fprintf_one_thread(struct thread *thread, void *priv)
3051{
3052 struct summary_data *data = priv;
3053 FILE *fp = data->fp;
3054 size_t printed = data->printed;
3055 struct trace *trace = data->trace;
89dceb22 3056 struct thread_trace *ttrace = thread__priv(thread);
896cbb56
DA
3057 double ratio;
3058
3059 if (ttrace == NULL)
3060 return 0;
3061
3062 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
3063
15e65c69 3064 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
99ff7150 3065 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
15e65c69 3066 printed += fprintf(fp, "%.1f%%", ratio);
a2ea67d7
SF
3067 if (ttrace->pfmaj)
3068 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
3069 if (ttrace->pfmin)
3070 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
99ff7150 3071 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
bf2575c1 3072 printed += thread__dump_stats(ttrace, trace, fp);
896cbb56
DA
3073
3074 data->printed += printed;
3075
3076 return 0;
3077}
3078
1302d88e
ACM
3079static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
3080{
896cbb56
DA
3081 struct summary_data data = {
3082 .fp = fp,
3083 .trace = trace
3084 };
3085 data.printed = trace__fprintf_threads_header(fp);
1302d88e 3086
896cbb56
DA
3087 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
3088
3089 return data.printed;
1302d88e
ACM
3090}
3091
ae9ed035
ACM
3092static int trace__set_duration(const struct option *opt, const char *str,
3093 int unset __maybe_unused)
3094{
3095 struct trace *trace = opt->value;
3096
3097 trace->duration_filter = atof(str);
3098 return 0;
3099}
3100
f078c385
ACM
3101static int trace__set_filter_pids(const struct option *opt, const char *str,
3102 int unset __maybe_unused)
3103{
3104 int ret = -1;
3105 size_t i;
3106 struct trace *trace = opt->value;
3107 /*
3108 * FIXME: introduce a intarray class, plain parse csv and create a
3109 * { int nr, int entries[] } struct...
3110 */
3111 struct intlist *list = intlist__new(str);
3112
3113 if (list == NULL)
3114 return -1;
3115
3116 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
3117 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
3118
3119 if (trace->filter_pids.entries == NULL)
3120 goto out;
3121
3122 trace->filter_pids.entries[0] = getpid();
3123
3124 for (i = 1; i < trace->filter_pids.nr; ++i)
3125 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
3126
3127 intlist__delete(list);
3128 ret = 0;
3129out:
3130 return ret;
3131}
3132
c24ff998
ACM
3133static int trace__open_output(struct trace *trace, const char *filename)
3134{
3135 struct stat st;
3136
3137 if (!stat(filename, &st) && st.st_size) {
3138 char oldname[PATH_MAX];
3139
3140 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
3141 unlink(oldname);
3142 rename(filename, oldname);
3143 }
3144
3145 trace->output = fopen(filename, "w");
3146
3147 return trace->output == NULL ? -errno : 0;
3148}
3149
598d02c5
SF
3150static int parse_pagefaults(const struct option *opt, const char *str,
3151 int unset __maybe_unused)
3152{
3153 int *trace_pgfaults = opt->value;
3154
3155 if (strcmp(str, "all") == 0)
3156 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
3157 else if (strcmp(str, "maj") == 0)
3158 *trace_pgfaults |= TRACE_PFMAJ;
3159 else if (strcmp(str, "min") == 0)
3160 *trace_pgfaults |= TRACE_PFMIN;
3161 else
3162 return -1;
3163
3164 return 0;
3165}
3166
14a052df
ACM
3167static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3168{
3169 struct perf_evsel *evsel;
3170
3171 evlist__for_each(evlist, evsel)
3172 evsel->handler = handler;
3173}
3174
514f1c67
ACM
3175int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3176{
6fdd9cb7 3177 const char *trace_usage[] = {
f15eb531
NK
3178 "perf trace [<options>] [<command>]",
3179 "perf trace [<options>] -- <command> [<options>]",
5e2485b1
DA
3180 "perf trace record [<options>] [<command>]",
3181 "perf trace record [<options>] -- <command> [<options>]",
514f1c67
ACM
3182 NULL
3183 };
3184 struct trace trace = {
c522739d
ACM
3185 .audit = {
3186 .machine = audit_detect_machine(),
3187 .open_id = audit_name_to_syscall("open", trace.audit.machine),
3188 },
514f1c67
ACM
3189 .syscalls = {
3190 . max = -1,
3191 },
3192 .opts = {
3193 .target = {
3194 .uid = UINT_MAX,
3195 .uses_mmap = true,
3196 },
3197 .user_freq = UINT_MAX,
3198 .user_interval = ULLONG_MAX,
509051ea 3199 .no_buffering = true,
38d5447d 3200 .mmap_pages = UINT_MAX,
9d9cad76 3201 .proc_map_timeout = 500,
514f1c67 3202 },
007d66a0 3203 .output = stderr,
50c95cbd 3204 .show_comm = true,
e281a960 3205 .trace_syscalls = true,
514f1c67 3206 };
c24ff998 3207 const char *output_name = NULL;
2ae3a312 3208 const char *ev_qualifier_str = NULL;
514f1c67 3209 const struct option trace_options[] = {
14a052df
ACM
3210 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3211 "event selector. use 'perf list' to list available events",
3212 parse_events_option),
50c95cbd
ACM
3213 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3214 "show the thread COMM next to its id"),
c522739d 3215 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
d303e85a 3216 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
c24ff998 3217 OPT_STRING('o', "output", &output_name, "file", "output file name"),
6810fc91 3218 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
514f1c67
ACM
3219 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3220 "trace events on existing process id"),
ac9be8ee 3221 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
514f1c67 3222 "trace events on existing thread id"),
fa0e4ffe
ACM
3223 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3224 "pids to filter (by the kernel)", trace__set_filter_pids),
ac9be8ee 3225 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
514f1c67 3226 "system-wide collection from all CPUs"),
ac9be8ee 3227 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
514f1c67 3228 "list of cpus to monitor"),
6810fc91 3229 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
514f1c67 3230 "child tasks do not inherit counters"),
994a1f78
JO
3231 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3232 "number of mmap data pages",
3233 perf_evlist__parse_mmap_pages),
ac9be8ee 3234 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
514f1c67 3235 "user to profile"),
ae9ed035
ACM
3236 OPT_CALLBACK(0, "duration", &trace, "float",
3237 "show only events with duration > N.M ms",
3238 trace__set_duration),
1302d88e 3239 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
7c304ee0 3240 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
4bb09192
DA
3241 OPT_BOOLEAN('T', "time", &trace.full_time,
3242 "Show full timestamp, not time relative to first start"),
fd2eabaf
DA
3243 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3244 "Show only syscall summary with statistics"),
3245 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3246 "Show all syscalls and summary with statistics"),
598d02c5
SF
3247 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3248 "Trace pagefaults", parse_pagefaults, "maj"),
e281a960 3249 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
e366a6d8 3250 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
9d9cad76
KL
3251 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3252 "per thread proc mmap processing timeout in ms"),
514f1c67
ACM
3253 OPT_END()
3254 };
6fdd9cb7 3255 const char * const trace_subcommands[] = { "record", NULL };
514f1c67 3256 int err;
32caf0d1 3257 char bf[BUFSIZ];
514f1c67 3258
4d08cb80
ACM
3259 signal(SIGSEGV, sighandler_dump_stack);
3260 signal(SIGFPE, sighandler_dump_stack);
3261
14a052df 3262 trace.evlist = perf_evlist__new();
14a052df
ACM
3263
3264 if (trace.evlist == NULL) {
3265 pr_err("Not enough memory to run!\n");
ff8f695c 3266 err = -ENOMEM;
14a052df
ACM
3267 goto out;
3268 }
3269
6fdd9cb7
YS
3270 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3271 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
fd2eabaf 3272
598d02c5
SF
3273 if (trace.trace_pgfaults) {
3274 trace.opts.sample_address = true;
3275 trace.opts.sample_time = true;
3276 }
3277
14a052df
ACM
3278 if (trace.evlist->nr_entries > 0)
3279 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3280
1e28fe0a
SF
3281 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3282 return trace__record(&trace, argc-1, &argv[1]);
3283
3284 /* summary_only implies summary option, but don't overwrite summary if set */
3285 if (trace.summary_only)
3286 trace.summary = trace.summary_only;
3287
726f3234
ACM
3288 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3289 trace.evlist->nr_entries == 0 /* Was --events used? */) {
e281a960
SF
3290 pr_err("Please specify something to trace.\n");
3291 return -1;
3292 }
3293
c24ff998
ACM
3294 if (output_name != NULL) {
3295 err = trace__open_output(&trace, output_name);
3296 if (err < 0) {
3297 perror("failed to create output file");
3298 goto out;
3299 }
3300 }
3301
2ae3a312 3302 if (ev_qualifier_str != NULL) {
b059efdf 3303 const char *s = ev_qualifier_str;
005438a8
ACM
3304 struct strlist_config slist_config = {
3305 .dirname = system_path(STRACE_GROUPS_DIR),
3306 };
b059efdf
ACM
3307
3308 trace.not_ev_qualifier = *s == '!';
3309 if (trace.not_ev_qualifier)
3310 ++s;
005438a8 3311 trace.ev_qualifier = strlist__new(s, &slist_config);
2ae3a312 3312 if (trace.ev_qualifier == NULL) {
c24ff998
ACM
3313 fputs("Not enough memory to parse event qualifier",
3314 trace.output);
3315 err = -ENOMEM;
3316 goto out_close;
2ae3a312 3317 }
d0cc439b
ACM
3318
3319 err = trace__validate_ev_qualifier(&trace);
3320 if (err)
3321 goto out_close;
2ae3a312
ACM
3322 }
3323
602ad878 3324 err = target__validate(&trace.opts.target);
32caf0d1 3325 if (err) {
602ad878 3326 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
3327 fprintf(trace.output, "%s", bf);
3328 goto out_close;
32caf0d1
NK
3329 }
3330
602ad878 3331 err = target__parse_uid(&trace.opts.target);
514f1c67 3332 if (err) {
602ad878 3333 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
3334 fprintf(trace.output, "%s", bf);
3335 goto out_close;
514f1c67
ACM
3336 }
3337
602ad878 3338 if (!argc && target__none(&trace.opts.target))
ee76120e
NK
3339 trace.opts.target.system_wide = true;
3340
6810fc91
DA
3341 if (input_name)
3342 err = trace__replay(&trace);
3343 else
3344 err = trace__run(&trace, argc, argv);
1302d88e 3345
c24ff998
ACM
3346out_close:
3347 if (output_name != NULL)
3348 fclose(trace.output);
3349out:
1302d88e 3350 return err;
514f1c67 3351}