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