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