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