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