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