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