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