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