]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - tools/perf/builtin-trace.c
perf evlist: Move destruction of maps to evlist destructor
[mirror_ubuntu-bionic-kernel.git] / tools / perf / builtin-trace.c
CommitLineData
4e319027 1#include <traceevent/event-parse.h>
514f1c67 2#include "builtin.h"
752fde44 3#include "util/color.h"
7c304ee0 4#include "util/debug.h"
514f1c67 5#include "util/evlist.h"
752fde44 6#include "util/machine.h"
6810fc91 7#include "util/session.h"
752fde44 8#include "util/thread.h"
514f1c67 9#include "util/parse-options.h"
2ae3a312 10#include "util/strlist.h"
bdc89661 11#include "util/intlist.h"
514f1c67 12#include "util/thread_map.h"
bf2575c1 13#include "util/stat.h"
97978b3e 14#include "trace-event.h"
9aca7f17 15#include "util/parse-events.h"
514f1c67
ACM
16
17#include <libaudit.h>
18#include <stdlib.h>
49af9e93 19#include <sys/eventfd.h>
ae685380 20#include <sys/mman.h>
f9da0b0c 21#include <linux/futex.h>
514f1c67 22
456857bd
IM
23/* For older distros: */
24#ifndef MAP_STACK
25# define MAP_STACK 0x20000
26#endif
27
28#ifndef MADV_HWPOISON
29# define MADV_HWPOISON 100
30#endif
31
32#ifndef MADV_MERGEABLE
33# define MADV_MERGEABLE 12
34#endif
35
36#ifndef MADV_UNMERGEABLE
37# define MADV_UNMERGEABLE 13
38#endif
39
77170988
ACM
40struct tp_field {
41 int offset;
42 union {
43 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
44 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
45 };
46};
47
48#define TP_UINT_FIELD(bits) \
49static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
50{ \
51 return *(u##bits *)(sample->raw_data + field->offset); \
52}
53
54TP_UINT_FIELD(8);
55TP_UINT_FIELD(16);
56TP_UINT_FIELD(32);
57TP_UINT_FIELD(64);
58
59#define TP_UINT_FIELD__SWAPPED(bits) \
60static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
61{ \
62 u##bits value = *(u##bits *)(sample->raw_data + field->offset); \
63 return bswap_##bits(value);\
64}
65
66TP_UINT_FIELD__SWAPPED(16);
67TP_UINT_FIELD__SWAPPED(32);
68TP_UINT_FIELD__SWAPPED(64);
69
70static int tp_field__init_uint(struct tp_field *field,
71 struct format_field *format_field,
72 bool needs_swap)
73{
74 field->offset = format_field->offset;
75
76 switch (format_field->size) {
77 case 1:
78 field->integer = tp_field__u8;
79 break;
80 case 2:
81 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
82 break;
83 case 4:
84 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
85 break;
86 case 8:
87 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
88 break;
89 default:
90 return -1;
91 }
92
93 return 0;
94}
95
96static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
97{
98 return sample->raw_data + field->offset;
99}
100
101static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
102{
103 field->offset = format_field->offset;
104 field->pointer = tp_field__ptr;
105 return 0;
106}
107
108struct syscall_tp {
109 struct tp_field id;
110 union {
111 struct tp_field args, ret;
112 };
113};
114
115static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
116 struct tp_field *field,
117 const char *name)
118{
119 struct format_field *format_field = perf_evsel__field(evsel, name);
120
121 if (format_field == NULL)
122 return -1;
123
124 return tp_field__init_uint(field, format_field, evsel->needs_swap);
125}
126
127#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
128 ({ struct syscall_tp *sc = evsel->priv;\
129 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
130
131static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
132 struct tp_field *field,
133 const char *name)
134{
135 struct format_field *format_field = perf_evsel__field(evsel, name);
136
137 if (format_field == NULL)
138 return -1;
139
140 return tp_field__init_ptr(field, format_field);
141}
142
143#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
144 ({ struct syscall_tp *sc = evsel->priv;\
145 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
146
147static void perf_evsel__delete_priv(struct perf_evsel *evsel)
148{
04662523 149 zfree(&evsel->priv);
77170988
ACM
150 perf_evsel__delete(evsel);
151}
152
96695d44
NK
153static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
154{
155 evsel->priv = malloc(sizeof(struct syscall_tp));
156 if (evsel->priv != NULL) {
157 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
158 goto out_delete;
159
160 evsel->handler = handler;
161 return 0;
162 }
163
164 return -ENOMEM;
165
166out_delete:
04662523 167 zfree(&evsel->priv);
96695d44
NK
168 return -ENOENT;
169}
170
ef503831 171static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
77170988 172{
ef503831 173 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
77170988 174
9aca7f17
DA
175 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
176 if (evsel == NULL)
177 evsel = perf_evsel__newtp("syscalls", direction);
178
77170988 179 if (evsel) {
96695d44 180 if (perf_evsel__init_syscall_tp(evsel, handler))
77170988 181 goto out_delete;
77170988
ACM
182 }
183
184 return evsel;
185
186out_delete:
187 perf_evsel__delete_priv(evsel);
188 return NULL;
189}
190
191#define perf_evsel__sc_tp_uint(evsel, name, sample) \
192 ({ struct syscall_tp *fields = evsel->priv; \
193 fields->name.integer(&fields->name, sample); })
194
195#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
196 ({ struct syscall_tp *fields = evsel->priv; \
197 fields->name.pointer(&fields->name, sample); })
198
199static int perf_evlist__add_syscall_newtp(struct perf_evlist *evlist,
200 void *sys_enter_handler,
201 void *sys_exit_handler)
202{
203 int ret = -1;
77170988
ACM
204 struct perf_evsel *sys_enter, *sys_exit;
205
ef503831 206 sys_enter = perf_evsel__syscall_newtp("sys_enter", sys_enter_handler);
77170988
ACM
207 if (sys_enter == NULL)
208 goto out;
209
210 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
211 goto out_delete_sys_enter;
212
ef503831 213 sys_exit = perf_evsel__syscall_newtp("sys_exit", sys_exit_handler);
77170988
ACM
214 if (sys_exit == NULL)
215 goto out_delete_sys_enter;
216
217 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
218 goto out_delete_sys_exit;
219
220 perf_evlist__add(evlist, sys_enter);
221 perf_evlist__add(evlist, sys_exit);
222
223 ret = 0;
224out:
225 return ret;
226
227out_delete_sys_exit:
228 perf_evsel__delete_priv(sys_exit);
229out_delete_sys_enter:
230 perf_evsel__delete_priv(sys_enter);
231 goto out;
232}
233
234
01533e97
ACM
235struct syscall_arg {
236 unsigned long val;
75b757ca
ACM
237 struct thread *thread;
238 struct trace *trace;
1f115cb7 239 void *parm;
01533e97
ACM
240 u8 idx;
241 u8 mask;
242};
243
1f115cb7 244struct strarray {
03e3adc9 245 int offset;
1f115cb7
ACM
246 int nr_entries;
247 const char **entries;
248};
249
250#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
251 .nr_entries = ARRAY_SIZE(array), \
252 .entries = array, \
253}
254
03e3adc9
ACM
255#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
256 .offset = off, \
257 .nr_entries = ARRAY_SIZE(array), \
258 .entries = array, \
259}
260
975b7c2f
ACM
261static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
262 const char *intfmt,
263 struct syscall_arg *arg)
1f115cb7 264{
1f115cb7 265 struct strarray *sa = arg->parm;
03e3adc9 266 int idx = arg->val - sa->offset;
1f115cb7
ACM
267
268 if (idx < 0 || idx >= sa->nr_entries)
975b7c2f 269 return scnprintf(bf, size, intfmt, arg->val);
1f115cb7
ACM
270
271 return scnprintf(bf, size, "%s", sa->entries[idx]);
272}
273
975b7c2f
ACM
274static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
275 struct syscall_arg *arg)
276{
277 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
278}
279
1f115cb7
ACM
280#define SCA_STRARRAY syscall_arg__scnprintf_strarray
281
78645cf3
ACM
282static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
283 struct syscall_arg *arg)
284{
285 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
286}
287
288#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
289
75b757ca
ACM
290static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
291 struct syscall_arg *arg);
292
293#define SCA_FD syscall_arg__scnprintf_fd
294
295static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
296 struct syscall_arg *arg)
297{
298 int fd = arg->val;
299
300 if (fd == AT_FDCWD)
301 return scnprintf(bf, size, "CWD");
302
303 return syscall_arg__scnprintf_fd(bf, size, arg);
304}
305
306#define SCA_FDAT syscall_arg__scnprintf_fd_at
307
308static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
309 struct syscall_arg *arg);
310
311#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
312
6e7eeb51 313static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
01533e97 314 struct syscall_arg *arg)
13d4ff3e 315{
01533e97 316 return scnprintf(bf, size, "%#lx", arg->val);
13d4ff3e
ACM
317}
318
beccb2b5
ACM
319#define SCA_HEX syscall_arg__scnprintf_hex
320
6e7eeb51 321static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
01533e97 322 struct syscall_arg *arg)
ae685380 323{
01533e97 324 int printed = 0, prot = arg->val;
ae685380
ACM
325
326 if (prot == PROT_NONE)
327 return scnprintf(bf, size, "NONE");
328#define P_MMAP_PROT(n) \
329 if (prot & PROT_##n) { \
330 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
331 prot &= ~PROT_##n; \
332 }
333
334 P_MMAP_PROT(EXEC);
335 P_MMAP_PROT(READ);
336 P_MMAP_PROT(WRITE);
337#ifdef PROT_SEM
338 P_MMAP_PROT(SEM);
339#endif
340 P_MMAP_PROT(GROWSDOWN);
341 P_MMAP_PROT(GROWSUP);
342#undef P_MMAP_PROT
343
344 if (prot)
345 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
346
347 return printed;
348}
349
350#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
351
6e7eeb51 352static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
01533e97 353 struct syscall_arg *arg)
941557e0 354{
01533e97 355 int printed = 0, flags = arg->val;
941557e0
ACM
356
357#define P_MMAP_FLAG(n) \
358 if (flags & MAP_##n) { \
359 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
360 flags &= ~MAP_##n; \
361 }
362
363 P_MMAP_FLAG(SHARED);
364 P_MMAP_FLAG(PRIVATE);
41817815 365#ifdef MAP_32BIT
941557e0 366 P_MMAP_FLAG(32BIT);
41817815 367#endif
941557e0
ACM
368 P_MMAP_FLAG(ANONYMOUS);
369 P_MMAP_FLAG(DENYWRITE);
370 P_MMAP_FLAG(EXECUTABLE);
371 P_MMAP_FLAG(FILE);
372 P_MMAP_FLAG(FIXED);
373 P_MMAP_FLAG(GROWSDOWN);
f2935f3e 374#ifdef MAP_HUGETLB
941557e0 375 P_MMAP_FLAG(HUGETLB);
f2935f3e 376#endif
941557e0
ACM
377 P_MMAP_FLAG(LOCKED);
378 P_MMAP_FLAG(NONBLOCK);
379 P_MMAP_FLAG(NORESERVE);
380 P_MMAP_FLAG(POPULATE);
381 P_MMAP_FLAG(STACK);
382#ifdef MAP_UNINITIALIZED
383 P_MMAP_FLAG(UNINITIALIZED);
384#endif
385#undef P_MMAP_FLAG
386
387 if (flags)
388 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
389
390 return printed;
391}
392
393#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
394
6e7eeb51 395static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
01533e97 396 struct syscall_arg *arg)
9e9716d1 397{
01533e97 398 int behavior = arg->val;
9e9716d1
ACM
399
400 switch (behavior) {
401#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
402 P_MADV_BHV(NORMAL);
403 P_MADV_BHV(RANDOM);
404 P_MADV_BHV(SEQUENTIAL);
405 P_MADV_BHV(WILLNEED);
406 P_MADV_BHV(DONTNEED);
407 P_MADV_BHV(REMOVE);
408 P_MADV_BHV(DONTFORK);
409 P_MADV_BHV(DOFORK);
410 P_MADV_BHV(HWPOISON);
411#ifdef MADV_SOFT_OFFLINE
412 P_MADV_BHV(SOFT_OFFLINE);
413#endif
414 P_MADV_BHV(MERGEABLE);
415 P_MADV_BHV(UNMERGEABLE);
f2935f3e 416#ifdef MADV_HUGEPAGE
9e9716d1 417 P_MADV_BHV(HUGEPAGE);
f2935f3e
DA
418#endif
419#ifdef MADV_NOHUGEPAGE
9e9716d1 420 P_MADV_BHV(NOHUGEPAGE);
f2935f3e 421#endif
9e9716d1
ACM
422#ifdef MADV_DONTDUMP
423 P_MADV_BHV(DONTDUMP);
424#endif
425#ifdef MADV_DODUMP
426 P_MADV_BHV(DODUMP);
427#endif
428#undef P_MADV_PHV
429 default: break;
430 }
431
432 return scnprintf(bf, size, "%#x", behavior);
433}
434
435#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
436
5cea6ff2
ACM
437static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
438 struct syscall_arg *arg)
439{
440 int printed = 0, op = arg->val;
441
442 if (op == 0)
443 return scnprintf(bf, size, "NONE");
444#define P_CMD(cmd) \
445 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
446 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
447 op &= ~LOCK_##cmd; \
448 }
449
450 P_CMD(SH);
451 P_CMD(EX);
452 P_CMD(NB);
453 P_CMD(UN);
454 P_CMD(MAND);
455 P_CMD(RW);
456 P_CMD(READ);
457 P_CMD(WRITE);
458#undef P_OP
459
460 if (op)
461 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
462
463 return printed;
464}
465
466#define SCA_FLOCK syscall_arg__scnprintf_flock
467
01533e97 468static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
f9da0b0c
ACM
469{
470 enum syscall_futex_args {
471 SCF_UADDR = (1 << 0),
472 SCF_OP = (1 << 1),
473 SCF_VAL = (1 << 2),
474 SCF_TIMEOUT = (1 << 3),
475 SCF_UADDR2 = (1 << 4),
476 SCF_VAL3 = (1 << 5),
477 };
01533e97 478 int op = arg->val;
f9da0b0c
ACM
479 int cmd = op & FUTEX_CMD_MASK;
480 size_t printed = 0;
481
482 switch (cmd) {
483#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
01533e97
ACM
484 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
485 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
486 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
487 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
488 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
489 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
f9da0b0c 490 P_FUTEX_OP(WAKE_OP); break;
01533e97
ACM
491 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
492 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
493 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
494 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
495 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
f9da0b0c
ACM
496 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
497 default: printed = scnprintf(bf, size, "%#x", cmd); break;
498 }
499
500 if (op & FUTEX_PRIVATE_FLAG)
501 printed += scnprintf(bf + printed, size - printed, "|PRIV");
502
503 if (op & FUTEX_CLOCK_REALTIME)
504 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
505
506 return printed;
507}
508
efe6b882
ACM
509#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
510
03e3adc9
ACM
511static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
512static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
eac032c5 513
1f115cb7
ACM
514static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
515static DEFINE_STRARRAY(itimers);
516
efe6b882
ACM
517static const char *whences[] = { "SET", "CUR", "END",
518#ifdef SEEK_DATA
519"DATA",
520#endif
521#ifdef SEEK_HOLE
522"HOLE",
523#endif
524};
525static DEFINE_STRARRAY(whences);
f9da0b0c 526
80f587d5
ACM
527static const char *fcntl_cmds[] = {
528 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
529 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
530 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
531 "F_GETOWNER_UIDS",
532};
533static DEFINE_STRARRAY(fcntl_cmds);
534
c045bf02
ACM
535static const char *rlimit_resources[] = {
536 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
537 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
538 "RTTIME",
539};
540static DEFINE_STRARRAY(rlimit_resources);
541
eb5b1b14
ACM
542static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
543static DEFINE_STRARRAY(sighow);
544
4f8c1b74
DA
545static const char *clockid[] = {
546 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
547 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
548};
549static DEFINE_STRARRAY(clockid);
550
e10bce81
ACM
551static const char *socket_families[] = {
552 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
553 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
554 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
555 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
556 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
557 "ALG", "NFC", "VSOCK",
558};
559static DEFINE_STRARRAY(socket_families);
560
a28b24b2
ACM
561#ifndef SOCK_TYPE_MASK
562#define SOCK_TYPE_MASK 0xf
563#endif
564
565static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
566 struct syscall_arg *arg)
567{
568 size_t printed;
569 int type = arg->val,
570 flags = type & ~SOCK_TYPE_MASK;
571
572 type &= SOCK_TYPE_MASK;
573 /*
574 * Can't use a strarray, MIPS may override for ABI reasons.
575 */
576 switch (type) {
577#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
578 P_SK_TYPE(STREAM);
579 P_SK_TYPE(DGRAM);
580 P_SK_TYPE(RAW);
581 P_SK_TYPE(RDM);
582 P_SK_TYPE(SEQPACKET);
583 P_SK_TYPE(DCCP);
584 P_SK_TYPE(PACKET);
585#undef P_SK_TYPE
586 default:
587 printed = scnprintf(bf, size, "%#x", type);
588 }
589
590#define P_SK_FLAG(n) \
591 if (flags & SOCK_##n) { \
592 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
593 flags &= ~SOCK_##n; \
594 }
595
596 P_SK_FLAG(CLOEXEC);
597 P_SK_FLAG(NONBLOCK);
598#undef P_SK_FLAG
599
600 if (flags)
601 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
602
603 return printed;
604}
605
606#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
607
b2cc99fd
ACM
608#ifndef MSG_PROBE
609#define MSG_PROBE 0x10
610#endif
b6e8f8f4
DA
611#ifndef MSG_WAITFORONE
612#define MSG_WAITFORONE 0x10000
613#endif
b2cc99fd
ACM
614#ifndef MSG_SENDPAGE_NOTLAST
615#define MSG_SENDPAGE_NOTLAST 0x20000
616#endif
617#ifndef MSG_FASTOPEN
618#define MSG_FASTOPEN 0x20000000
619#endif
620
621static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
622 struct syscall_arg *arg)
623{
624 int printed = 0, flags = arg->val;
625
626 if (flags == 0)
627 return scnprintf(bf, size, "NONE");
628#define P_MSG_FLAG(n) \
629 if (flags & MSG_##n) { \
630 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
631 flags &= ~MSG_##n; \
632 }
633
634 P_MSG_FLAG(OOB);
635 P_MSG_FLAG(PEEK);
636 P_MSG_FLAG(DONTROUTE);
637 P_MSG_FLAG(TRYHARD);
638 P_MSG_FLAG(CTRUNC);
639 P_MSG_FLAG(PROBE);
640 P_MSG_FLAG(TRUNC);
641 P_MSG_FLAG(DONTWAIT);
642 P_MSG_FLAG(EOR);
643 P_MSG_FLAG(WAITALL);
644 P_MSG_FLAG(FIN);
645 P_MSG_FLAG(SYN);
646 P_MSG_FLAG(CONFIRM);
647 P_MSG_FLAG(RST);
648 P_MSG_FLAG(ERRQUEUE);
649 P_MSG_FLAG(NOSIGNAL);
650 P_MSG_FLAG(MORE);
651 P_MSG_FLAG(WAITFORONE);
652 P_MSG_FLAG(SENDPAGE_NOTLAST);
653 P_MSG_FLAG(FASTOPEN);
654 P_MSG_FLAG(CMSG_CLOEXEC);
655#undef P_MSG_FLAG
656
657 if (flags)
658 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
659
660 return printed;
661}
662
663#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
664
51108999
ACM
665static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
666 struct syscall_arg *arg)
667{
668 size_t printed = 0;
669 int mode = arg->val;
670
671 if (mode == F_OK) /* 0 */
672 return scnprintf(bf, size, "F");
673#define P_MODE(n) \
674 if (mode & n##_OK) { \
675 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
676 mode &= ~n##_OK; \
677 }
678
679 P_MODE(R);
680 P_MODE(W);
681 P_MODE(X);
682#undef P_MODE
683
684 if (mode)
685 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
686
687 return printed;
688}
689
690#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
691
be65a89a 692static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
01533e97 693 struct syscall_arg *arg)
be65a89a 694{
01533e97 695 int printed = 0, flags = arg->val;
be65a89a
ACM
696
697 if (!(flags & O_CREAT))
01533e97 698 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
be65a89a
ACM
699
700 if (flags == 0)
701 return scnprintf(bf, size, "RDONLY");
702#define P_FLAG(n) \
703 if (flags & O_##n) { \
704 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
705 flags &= ~O_##n; \
706 }
707
708 P_FLAG(APPEND);
709 P_FLAG(ASYNC);
710 P_FLAG(CLOEXEC);
711 P_FLAG(CREAT);
712 P_FLAG(DIRECT);
713 P_FLAG(DIRECTORY);
714 P_FLAG(EXCL);
715 P_FLAG(LARGEFILE);
716 P_FLAG(NOATIME);
717 P_FLAG(NOCTTY);
718#ifdef O_NONBLOCK
719 P_FLAG(NONBLOCK);
720#elif O_NDELAY
721 P_FLAG(NDELAY);
722#endif
723#ifdef O_PATH
724 P_FLAG(PATH);
725#endif
726 P_FLAG(RDWR);
727#ifdef O_DSYNC
728 if ((flags & O_SYNC) == O_SYNC)
729 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
730 else {
731 P_FLAG(DSYNC);
732 }
733#else
734 P_FLAG(SYNC);
735#endif
736 P_FLAG(TRUNC);
737 P_FLAG(WRONLY);
738#undef P_FLAG
739
740 if (flags)
741 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
742
743 return printed;
744}
745
746#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
747
49af9e93
ACM
748static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
749 struct syscall_arg *arg)
750{
751 int printed = 0, flags = arg->val;
752
753 if (flags == 0)
754 return scnprintf(bf, size, "NONE");
755#define P_FLAG(n) \
756 if (flags & EFD_##n) { \
757 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
758 flags &= ~EFD_##n; \
759 }
760
761 P_FLAG(SEMAPHORE);
762 P_FLAG(CLOEXEC);
763 P_FLAG(NONBLOCK);
764#undef P_FLAG
765
766 if (flags)
767 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
768
769 return printed;
770}
771
772#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
773
46cce19b
ACM
774static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
775 struct syscall_arg *arg)
776{
777 int printed = 0, flags = arg->val;
778
779#define P_FLAG(n) \
780 if (flags & O_##n) { \
781 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
782 flags &= ~O_##n; \
783 }
784
785 P_FLAG(CLOEXEC);
786 P_FLAG(NONBLOCK);
787#undef P_FLAG
788
789 if (flags)
790 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
791
792 return printed;
793}
794
795#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
796
8bad5b0a
ACM
797static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
798{
799 int sig = arg->val;
800
801 switch (sig) {
802#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
803 P_SIGNUM(HUP);
804 P_SIGNUM(INT);
805 P_SIGNUM(QUIT);
806 P_SIGNUM(ILL);
807 P_SIGNUM(TRAP);
808 P_SIGNUM(ABRT);
809 P_SIGNUM(BUS);
810 P_SIGNUM(FPE);
811 P_SIGNUM(KILL);
812 P_SIGNUM(USR1);
813 P_SIGNUM(SEGV);
814 P_SIGNUM(USR2);
815 P_SIGNUM(PIPE);
816 P_SIGNUM(ALRM);
817 P_SIGNUM(TERM);
818 P_SIGNUM(STKFLT);
819 P_SIGNUM(CHLD);
820 P_SIGNUM(CONT);
821 P_SIGNUM(STOP);
822 P_SIGNUM(TSTP);
823 P_SIGNUM(TTIN);
824 P_SIGNUM(TTOU);
825 P_SIGNUM(URG);
826 P_SIGNUM(XCPU);
827 P_SIGNUM(XFSZ);
828 P_SIGNUM(VTALRM);
829 P_SIGNUM(PROF);
830 P_SIGNUM(WINCH);
831 P_SIGNUM(IO);
832 P_SIGNUM(PWR);
833 P_SIGNUM(SYS);
834 default: break;
835 }
836
837 return scnprintf(bf, size, "%#x", sig);
838}
839
840#define SCA_SIGNUM syscall_arg__scnprintf_signum
841
78645cf3
ACM
842#define TCGETS 0x5401
843
844static const char *tioctls[] = {
845 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
846 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
847 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
848 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
849 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
850 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
851 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
852 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
853 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
854 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
855 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
856 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
857 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
858 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
859 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
860};
861
862static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
863
453350dd
ACM
864#define STRARRAY(arg, name, array) \
865 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
866 .arg_parm = { [arg] = &strarray__##array, }
867
514f1c67
ACM
868static struct syscall_fmt {
869 const char *name;
aec1930b 870 const char *alias;
01533e97 871 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
1f115cb7 872 void *arg_parm[6];
514f1c67
ACM
873 bool errmsg;
874 bool timeout;
04b34729 875 bool hexret;
514f1c67 876} syscall_fmts[] = {
51108999
ACM
877 { .name = "access", .errmsg = true,
878 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
aec1930b 879 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
beccb2b5
ACM
880 { .name = "brk", .hexret = true,
881 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
4f8c1b74 882 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
75b757ca
ACM
883 { .name = "close", .errmsg = true,
884 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
a14bb860 885 { .name = "connect", .errmsg = true, },
75b757ca
ACM
886 { .name = "dup", .errmsg = true,
887 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
888 { .name = "dup2", .errmsg = true,
889 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
890 { .name = "dup3", .errmsg = true,
891 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
453350dd 892 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
49af9e93
ACM
893 { .name = "eventfd2", .errmsg = true,
894 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
75b757ca
ACM
895 { .name = "faccessat", .errmsg = true,
896 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
897 { .name = "fadvise64", .errmsg = true,
898 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
899 { .name = "fallocate", .errmsg = true,
900 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
901 { .name = "fchdir", .errmsg = true,
902 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
903 { .name = "fchmod", .errmsg = true,
904 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
905 { .name = "fchmodat", .errmsg = true,
906 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
907 { .name = "fchown", .errmsg = true,
908 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
909 { .name = "fchownat", .errmsg = true,
910 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
911 { .name = "fcntl", .errmsg = true,
912 .arg_scnprintf = { [0] = SCA_FD, /* fd */
913 [1] = SCA_STRARRAY, /* cmd */ },
914 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
915 { .name = "fdatasync", .errmsg = true,
916 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
5cea6ff2 917 { .name = "flock", .errmsg = true,
75b757ca
ACM
918 .arg_scnprintf = { [0] = SCA_FD, /* fd */
919 [1] = SCA_FLOCK, /* cmd */ }, },
920 { .name = "fsetxattr", .errmsg = true,
921 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
922 { .name = "fstat", .errmsg = true, .alias = "newfstat",
923 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
924 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
925 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
926 { .name = "fstatfs", .errmsg = true,
927 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
928 { .name = "fsync", .errmsg = true,
929 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
930 { .name = "ftruncate", .errmsg = true,
931 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
f9da0b0c
ACM
932 { .name = "futex", .errmsg = true,
933 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
75b757ca
ACM
934 { .name = "futimesat", .errmsg = true,
935 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
936 { .name = "getdents", .errmsg = true,
937 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
938 { .name = "getdents64", .errmsg = true,
939 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
453350dd
ACM
940 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
941 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
beccb2b5 942 { .name = "ioctl", .errmsg = true,
75b757ca 943 .arg_scnprintf = { [0] = SCA_FD, /* fd */
78645cf3
ACM
944 [1] = SCA_STRHEXARRAY, /* cmd */
945 [2] = SCA_HEX, /* arg */ },
946 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
8bad5b0a
ACM
947 { .name = "kill", .errmsg = true,
948 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
75b757ca
ACM
949 { .name = "linkat", .errmsg = true,
950 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
951 { .name = "lseek", .errmsg = true,
952 .arg_scnprintf = { [0] = SCA_FD, /* fd */
953 [2] = SCA_STRARRAY, /* whence */ },
954 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
e5959683 955 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
9e9716d1
ACM
956 { .name = "madvise", .errmsg = true,
957 .arg_scnprintf = { [0] = SCA_HEX, /* start */
958 [2] = SCA_MADV_BHV, /* behavior */ }, },
75b757ca
ACM
959 { .name = "mkdirat", .errmsg = true,
960 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
961 { .name = "mknodat", .errmsg = true,
962 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
3d903aa7
ACM
963 { .name = "mlock", .errmsg = true,
964 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
965 { .name = "mlockall", .errmsg = true,
966 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
beccb2b5 967 { .name = "mmap", .hexret = true,
ae685380 968 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
941557e0 969 [2] = SCA_MMAP_PROT, /* prot */
73faab3a
NK
970 [3] = SCA_MMAP_FLAGS, /* flags */
971 [4] = SCA_FD, /* fd */ }, },
beccb2b5 972 { .name = "mprotect", .errmsg = true,
ae685380
ACM
973 .arg_scnprintf = { [0] = SCA_HEX, /* start */
974 [2] = SCA_MMAP_PROT, /* prot */ }, },
975 { .name = "mremap", .hexret = true,
976 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
977 [4] = SCA_HEX, /* new_addr */ }, },
3d903aa7
ACM
978 { .name = "munlock", .errmsg = true,
979 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
beccb2b5
ACM
980 { .name = "munmap", .errmsg = true,
981 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
75b757ca
ACM
982 { .name = "name_to_handle_at", .errmsg = true,
983 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
984 { .name = "newfstatat", .errmsg = true,
985 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
be65a89a
ACM
986 { .name = "open", .errmsg = true,
987 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
31cd3855 988 { .name = "open_by_handle_at", .errmsg = true,
75b757ca
ACM
989 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
990 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
31cd3855 991 { .name = "openat", .errmsg = true,
75b757ca
ACM
992 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
993 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
46cce19b
ACM
994 { .name = "pipe2", .errmsg = true,
995 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
aec1930b
ACM
996 { .name = "poll", .errmsg = true, .timeout = true, },
997 { .name = "ppoll", .errmsg = true, .timeout = true, },
75b757ca
ACM
998 { .name = "pread", .errmsg = true, .alias = "pread64",
999 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1000 { .name = "preadv", .errmsg = true, .alias = "pread",
1001 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
453350dd 1002 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
75b757ca
ACM
1003 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
1004 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1005 { .name = "pwritev", .errmsg = true,
1006 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1007 { .name = "read", .errmsg = true,
1008 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1009 { .name = "readlinkat", .errmsg = true,
1010 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1011 { .name = "readv", .errmsg = true,
1012 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
b2cc99fd
ACM
1013 { .name = "recvfrom", .errmsg = true,
1014 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1015 { .name = "recvmmsg", .errmsg = true,
1016 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1017 { .name = "recvmsg", .errmsg = true,
1018 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
75b757ca
ACM
1019 { .name = "renameat", .errmsg = true,
1020 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
8bad5b0a
ACM
1021 { .name = "rt_sigaction", .errmsg = true,
1022 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
453350dd 1023 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
8bad5b0a
ACM
1024 { .name = "rt_sigqueueinfo", .errmsg = true,
1025 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1026 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1027 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
aec1930b 1028 { .name = "select", .errmsg = true, .timeout = true, },
b2cc99fd
ACM
1029 { .name = "sendmmsg", .errmsg = true,
1030 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1031 { .name = "sendmsg", .errmsg = true,
1032 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
1033 { .name = "sendto", .errmsg = true,
1034 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
453350dd
ACM
1035 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1036 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
75b757ca
ACM
1037 { .name = "shutdown", .errmsg = true,
1038 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
e10bce81 1039 { .name = "socket", .errmsg = true,
a28b24b2
ACM
1040 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1041 [1] = SCA_SK_TYPE, /* type */ },
07120aa5
ACM
1042 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
1043 { .name = "socketpair", .errmsg = true,
1044 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1045 [1] = SCA_SK_TYPE, /* type */ },
e10bce81 1046 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
aec1930b 1047 { .name = "stat", .errmsg = true, .alias = "newstat", },
75b757ca
ACM
1048 { .name = "symlinkat", .errmsg = true,
1049 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
8bad5b0a
ACM
1050 { .name = "tgkill", .errmsg = true,
1051 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1052 { .name = "tkill", .errmsg = true,
1053 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
e5959683 1054 { .name = "uname", .errmsg = true, .alias = "newuname", },
75b757ca
ACM
1055 { .name = "unlinkat", .errmsg = true,
1056 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1057 { .name = "utimensat", .errmsg = true,
1058 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
1059 { .name = "write", .errmsg = true,
1060 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1061 { .name = "writev", .errmsg = true,
1062 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
514f1c67
ACM
1063};
1064
1065static int syscall_fmt__cmp(const void *name, const void *fmtp)
1066{
1067 const struct syscall_fmt *fmt = fmtp;
1068 return strcmp(name, fmt->name);
1069}
1070
1071static struct syscall_fmt *syscall_fmt__find(const char *name)
1072{
1073 const int nmemb = ARRAY_SIZE(syscall_fmts);
1074 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1075}
1076
1077struct syscall {
1078 struct event_format *tp_format;
1079 const char *name;
2ae3a312 1080 bool filtered;
514f1c67 1081 struct syscall_fmt *fmt;
01533e97 1082 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
1f115cb7 1083 void **arg_parm;
514f1c67
ACM
1084};
1085
60c907ab
ACM
1086static size_t fprintf_duration(unsigned long t, FILE *fp)
1087{
1088 double duration = (double)t / NSEC_PER_MSEC;
1089 size_t printed = fprintf(fp, "(");
1090
1091 if (duration >= 1.0)
1092 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1093 else if (duration >= 0.01)
1094 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1095 else
1096 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
c24ff998 1097 return printed + fprintf(fp, "): ");
60c907ab
ACM
1098}
1099
752fde44
ACM
1100struct thread_trace {
1101 u64 entry_time;
1102 u64 exit_time;
1103 bool entry_pending;
efd5745e 1104 unsigned long nr_events;
752fde44 1105 char *entry_str;
1302d88e 1106 double runtime_ms;
75b757ca
ACM
1107 struct {
1108 int max;
1109 char **table;
1110 } paths;
bf2575c1
DA
1111
1112 struct intlist *syscall_stats;
752fde44
ACM
1113};
1114
1115static struct thread_trace *thread_trace__new(void)
1116{
75b757ca
ACM
1117 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1118
1119 if (ttrace)
1120 ttrace->paths.max = -1;
1121
bf2575c1
DA
1122 ttrace->syscall_stats = intlist__new(NULL);
1123
75b757ca 1124 return ttrace;
752fde44
ACM
1125}
1126
c24ff998 1127static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
752fde44 1128{
efd5745e
ACM
1129 struct thread_trace *ttrace;
1130
752fde44
ACM
1131 if (thread == NULL)
1132 goto fail;
1133
1134 if (thread->priv == NULL)
1135 thread->priv = thread_trace__new();
efd5745e 1136
752fde44
ACM
1137 if (thread->priv == NULL)
1138 goto fail;
1139
efd5745e
ACM
1140 ttrace = thread->priv;
1141 ++ttrace->nr_events;
1142
1143 return ttrace;
752fde44 1144fail:
c24ff998 1145 color_fprintf(fp, PERF_COLOR_RED,
752fde44
ACM
1146 "WARNING: not enough memory, dropping samples!\n");
1147 return NULL;
1148}
1149
514f1c67 1150struct trace {
c24ff998 1151 struct perf_tool tool;
c522739d
ACM
1152 struct {
1153 int machine;
1154 int open_id;
1155 } audit;
514f1c67
ACM
1156 struct {
1157 int max;
1158 struct syscall *table;
1159 } syscalls;
b4006796 1160 struct record_opts opts;
8fb598e5 1161 struct machine *host;
752fde44 1162 u64 base_time;
4bb09192 1163 bool full_time;
c24ff998 1164 FILE *output;
efd5745e 1165 unsigned long nr_events;
b059efdf
ACM
1166 struct strlist *ev_qualifier;
1167 bool not_ev_qualifier;
75b757ca 1168 bool live;
c522739d 1169 const char *last_vfs_getname;
bdc89661
DA
1170 struct intlist *tid_list;
1171 struct intlist *pid_list;
1302d88e 1172 bool sched;
752fde44 1173 bool multiple_threads;
bf2575c1 1174 bool summary;
fd2eabaf 1175 bool summary_only;
50c95cbd 1176 bool show_comm;
c522739d 1177 bool show_tool_stats;
ae9ed035 1178 double duration_filter;
1302d88e 1179 double runtime_ms;
c522739d
ACM
1180 struct {
1181 u64 vfs_getname, proc_getname;
1182 } stats;
514f1c67
ACM
1183};
1184
97119f37 1185static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
75b757ca
ACM
1186{
1187 struct thread_trace *ttrace = thread->priv;
75b757ca
ACM
1188
1189 if (fd > ttrace->paths.max) {
1190 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1191
1192 if (npath == NULL)
1193 return -1;
1194
1195 if (ttrace->paths.max != -1) {
1196 memset(npath + ttrace->paths.max + 1, 0,
1197 (fd - ttrace->paths.max) * sizeof(char *));
1198 } else {
1199 memset(npath, 0, (fd + 1) * sizeof(char *));
1200 }
1201
1202 ttrace->paths.table = npath;
1203 ttrace->paths.max = fd;
1204 }
1205
1206 ttrace->paths.table[fd] = strdup(pathname);
1207
1208 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1209}
1210
97119f37
ACM
1211static int thread__read_fd_path(struct thread *thread, int fd)
1212{
1213 char linkname[PATH_MAX], pathname[PATH_MAX];
1214 struct stat st;
1215 int ret;
1216
1217 if (thread->pid_ == thread->tid) {
1218 scnprintf(linkname, sizeof(linkname),
1219 "/proc/%d/fd/%d", thread->pid_, fd);
1220 } else {
1221 scnprintf(linkname, sizeof(linkname),
1222 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1223 }
1224
1225 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1226 return -1;
1227
1228 ret = readlink(linkname, pathname, sizeof(pathname));
1229
1230 if (ret < 0 || ret > st.st_size)
1231 return -1;
1232
1233 pathname[ret] = '\0';
1234 return trace__set_fd_pathname(thread, fd, pathname);
1235}
1236
c522739d
ACM
1237static const char *thread__fd_path(struct thread *thread, int fd,
1238 struct trace *trace)
75b757ca
ACM
1239{
1240 struct thread_trace *ttrace = thread->priv;
1241
1242 if (ttrace == NULL)
1243 return NULL;
1244
1245 if (fd < 0)
1246 return NULL;
1247
c522739d
ACM
1248 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL))
1249 if (!trace->live)
1250 return NULL;
1251 ++trace->stats.proc_getname;
1252 if (thread__read_fd_path(thread, fd)) {
1253 return NULL;
1254 }
75b757ca
ACM
1255
1256 return ttrace->paths.table[fd];
1257}
1258
1259static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1260 struct syscall_arg *arg)
1261{
1262 int fd = arg->val;
1263 size_t printed = scnprintf(bf, size, "%d", fd);
c522739d 1264 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
75b757ca
ACM
1265
1266 if (path)
1267 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1268
1269 return printed;
1270}
1271
1272static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1273 struct syscall_arg *arg)
1274{
1275 int fd = arg->val;
1276 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1277 struct thread_trace *ttrace = arg->thread->priv;
1278
04662523
ACM
1279 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1280 zfree(&ttrace->paths.table[fd]);
75b757ca
ACM
1281
1282 return printed;
1283}
1284
ae9ed035
ACM
1285static bool trace__filter_duration(struct trace *trace, double t)
1286{
1287 return t < (trace->duration_filter * NSEC_PER_MSEC);
1288}
1289
752fde44
ACM
1290static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1291{
1292 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1293
60c907ab 1294 return fprintf(fp, "%10.3f ", ts);
752fde44
ACM
1295}
1296
f15eb531 1297static bool done = false;
ba209f85 1298static bool interrupted = false;
f15eb531 1299
ba209f85 1300static void sig_handler(int sig)
f15eb531
NK
1301{
1302 done = true;
ba209f85 1303 interrupted = sig == SIGINT;
f15eb531
NK
1304}
1305
752fde44 1306static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
60c907ab 1307 u64 duration, u64 tstamp, FILE *fp)
752fde44
ACM
1308{
1309 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
60c907ab 1310 printed += fprintf_duration(duration, fp);
752fde44 1311
50c95cbd
ACM
1312 if (trace->multiple_threads) {
1313 if (trace->show_comm)
1902efe7 1314 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
38051234 1315 printed += fprintf(fp, "%d ", thread->tid);
50c95cbd 1316 }
752fde44
ACM
1317
1318 return printed;
1319}
1320
c24ff998 1321static int trace__process_event(struct trace *trace, struct machine *machine,
162f0bef 1322 union perf_event *event, struct perf_sample *sample)
752fde44
ACM
1323{
1324 int ret = 0;
1325
1326 switch (event->header.type) {
1327 case PERF_RECORD_LOST:
c24ff998 1328 color_fprintf(trace->output, PERF_COLOR_RED,
752fde44 1329 "LOST %" PRIu64 " events!\n", event->lost.lost);
162f0bef 1330 ret = machine__process_lost_event(machine, event, sample);
752fde44 1331 default:
162f0bef 1332 ret = machine__process_event(machine, event, sample);
752fde44
ACM
1333 break;
1334 }
1335
1336 return ret;
1337}
1338
c24ff998 1339static int trace__tool_process(struct perf_tool *tool,
752fde44 1340 union perf_event *event,
162f0bef 1341 struct perf_sample *sample,
752fde44
ACM
1342 struct machine *machine)
1343{
c24ff998 1344 struct trace *trace = container_of(tool, struct trace, tool);
162f0bef 1345 return trace__process_event(trace, machine, event, sample);
752fde44
ACM
1346}
1347
1348static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1349{
1350 int err = symbol__init();
1351
1352 if (err)
1353 return err;
1354
8fb598e5
DA
1355 trace->host = machine__new_host();
1356 if (trace->host == NULL)
1357 return -ENOMEM;
752fde44 1358
a33fbd56
ACM
1359 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
1360 evlist->threads, trace__tool_process, false);
752fde44
ACM
1361 if (err)
1362 symbol__exit();
1363
1364 return err;
1365}
1366
13d4ff3e
ACM
1367static int syscall__set_arg_fmts(struct syscall *sc)
1368{
1369 struct format_field *field;
1370 int idx = 0;
1371
1372 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1373 if (sc->arg_scnprintf == NULL)
1374 return -1;
1375
1f115cb7
ACM
1376 if (sc->fmt)
1377 sc->arg_parm = sc->fmt->arg_parm;
1378
13d4ff3e 1379 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
beccb2b5
ACM
1380 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1381 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1382 else if (field->flags & FIELD_IS_POINTER)
13d4ff3e
ACM
1383 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1384 ++idx;
1385 }
1386
1387 return 0;
1388}
1389
514f1c67
ACM
1390static int trace__read_syscall_info(struct trace *trace, int id)
1391{
1392 char tp_name[128];
1393 struct syscall *sc;
c522739d 1394 const char *name = audit_syscall_to_name(id, trace->audit.machine);
3a531260
ACM
1395
1396 if (name == NULL)
1397 return -1;
514f1c67
ACM
1398
1399 if (id > trace->syscalls.max) {
1400 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1401
1402 if (nsyscalls == NULL)
1403 return -1;
1404
1405 if (trace->syscalls.max != -1) {
1406 memset(nsyscalls + trace->syscalls.max + 1, 0,
1407 (id - trace->syscalls.max) * sizeof(*sc));
1408 } else {
1409 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1410 }
1411
1412 trace->syscalls.table = nsyscalls;
1413 trace->syscalls.max = id;
1414 }
1415
1416 sc = trace->syscalls.table + id;
3a531260 1417 sc->name = name;
2ae3a312 1418
b059efdf
ACM
1419 if (trace->ev_qualifier) {
1420 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1421
1422 if (!(in ^ trace->not_ev_qualifier)) {
1423 sc->filtered = true;
1424 /*
1425 * No need to do read tracepoint information since this will be
1426 * filtered out.
1427 */
1428 return 0;
1429 }
2ae3a312
ACM
1430 }
1431
3a531260 1432 sc->fmt = syscall_fmt__find(sc->name);
514f1c67 1433
aec1930b 1434 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
97978b3e 1435 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
aec1930b
ACM
1436
1437 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1438 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
97978b3e 1439 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
aec1930b 1440 }
514f1c67 1441
13d4ff3e
ACM
1442 if (sc->tp_format == NULL)
1443 return -1;
1444
1445 return syscall__set_arg_fmts(sc);
514f1c67
ACM
1446}
1447
752fde44 1448static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
75b757ca
ACM
1449 unsigned long *args, struct trace *trace,
1450 struct thread *thread)
514f1c67 1451{
514f1c67
ACM
1452 size_t printed = 0;
1453
1454 if (sc->tp_format != NULL) {
1455 struct format_field *field;
01533e97
ACM
1456 u8 bit = 1;
1457 struct syscall_arg arg = {
75b757ca
ACM
1458 .idx = 0,
1459 .mask = 0,
1460 .trace = trace,
1461 .thread = thread,
01533e97 1462 };
6e7eeb51
ACM
1463
1464 for (field = sc->tp_format->format.fields->next; field;
01533e97
ACM
1465 field = field->next, ++arg.idx, bit <<= 1) {
1466 if (arg.mask & bit)
6e7eeb51 1467 continue;
4aa58232
ACM
1468 /*
1469 * Suppress this argument if its value is zero and
1470 * and we don't have a string associated in an
1471 * strarray for it.
1472 */
1473 if (args[arg.idx] == 0 &&
1474 !(sc->arg_scnprintf &&
1475 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1476 sc->arg_parm[arg.idx]))
22ae5cf1
ACM
1477 continue;
1478
752fde44 1479 printed += scnprintf(bf + printed, size - printed,
13d4ff3e 1480 "%s%s: ", printed ? ", " : "", field->name);
01533e97
ACM
1481 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1482 arg.val = args[arg.idx];
1f115cb7
ACM
1483 if (sc->arg_parm)
1484 arg.parm = sc->arg_parm[arg.idx];
01533e97
ACM
1485 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1486 size - printed, &arg);
6e7eeb51 1487 } else {
13d4ff3e 1488 printed += scnprintf(bf + printed, size - printed,
01533e97 1489 "%ld", args[arg.idx]);
6e7eeb51 1490 }
514f1c67
ACM
1491 }
1492 } else {
01533e97
ACM
1493 int i = 0;
1494
514f1c67 1495 while (i < 6) {
752fde44
ACM
1496 printed += scnprintf(bf + printed, size - printed,
1497 "%sarg%d: %ld",
1498 printed ? ", " : "", i, args[i]);
514f1c67
ACM
1499 ++i;
1500 }
1501 }
1502
1503 return printed;
1504}
1505
ba3d7dee
ACM
1506typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1507 struct perf_sample *sample);
1508
1509static struct syscall *trace__syscall_info(struct trace *trace,
bf2575c1 1510 struct perf_evsel *evsel, int id)
ba3d7dee 1511{
ba3d7dee
ACM
1512
1513 if (id < 0) {
adaa18bf
ACM
1514
1515 /*
1516 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1517 * before that, leaving at a higher verbosity level till that is
1518 * explained. Reproduced with plain ftrace with:
1519 *
1520 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1521 * grep "NR -1 " /t/trace_pipe
1522 *
1523 * After generating some load on the machine.
1524 */
1525 if (verbose > 1) {
1526 static u64 n;
1527 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1528 id, perf_evsel__name(evsel), ++n);
1529 }
ba3d7dee
ACM
1530 return NULL;
1531 }
1532
1533 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1534 trace__read_syscall_info(trace, id))
1535 goto out_cant_read;
1536
1537 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1538 goto out_cant_read;
1539
1540 return &trace->syscalls.table[id];
1541
1542out_cant_read:
7c304ee0
ACM
1543 if (verbose) {
1544 fprintf(trace->output, "Problems reading syscall %d", id);
1545 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1546 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1547 fputs(" information\n", trace->output);
1548 }
ba3d7dee
ACM
1549 return NULL;
1550}
1551
bf2575c1
DA
1552static void thread__update_stats(struct thread_trace *ttrace,
1553 int id, struct perf_sample *sample)
1554{
1555 struct int_node *inode;
1556 struct stats *stats;
1557 u64 duration = 0;
1558
1559 inode = intlist__findnew(ttrace->syscall_stats, id);
1560 if (inode == NULL)
1561 return;
1562
1563 stats = inode->priv;
1564 if (stats == NULL) {
1565 stats = malloc(sizeof(struct stats));
1566 if (stats == NULL)
1567 return;
1568 init_stats(stats);
1569 inode->priv = stats;
1570 }
1571
1572 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1573 duration = sample->time - ttrace->entry_time;
1574
1575 update_stats(stats, duration);
1576}
1577
ba3d7dee
ACM
1578static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1579 struct perf_sample *sample)
1580{
752fde44 1581 char *msg;
ba3d7dee 1582 void *args;
752fde44 1583 size_t printed = 0;
2ae3a312 1584 struct thread *thread;
77170988 1585 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
bf2575c1 1586 struct syscall *sc = trace__syscall_info(trace, evsel, id);
2ae3a312
ACM
1587 struct thread_trace *ttrace;
1588
1589 if (sc == NULL)
1590 return -1;
ba3d7dee 1591
2ae3a312
ACM
1592 if (sc->filtered)
1593 return 0;
1594
8fb598e5 1595 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
c24ff998 1596 ttrace = thread__trace(thread, trace->output);
2ae3a312 1597 if (ttrace == NULL)
ba3d7dee
ACM
1598 return -1;
1599
77170988 1600 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
752fde44
ACM
1601 ttrace = thread->priv;
1602
1603 if (ttrace->entry_str == NULL) {
1604 ttrace->entry_str = malloc(1024);
1605 if (!ttrace->entry_str)
1606 return -1;
1607 }
1608
1609 ttrace->entry_time = sample->time;
1610 msg = ttrace->entry_str;
1611 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1612
75b757ca
ACM
1613 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1614 args, trace, thread);
752fde44
ACM
1615
1616 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
fd2eabaf 1617 if (!trace->duration_filter && !trace->summary_only) {
c24ff998
ACM
1618 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1619 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
ae9ed035 1620 }
752fde44
ACM
1621 } else
1622 ttrace->entry_pending = true;
ba3d7dee
ACM
1623
1624 return 0;
1625}
1626
1627static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1628 struct perf_sample *sample)
1629{
1630 int ret;
60c907ab 1631 u64 duration = 0;
2ae3a312 1632 struct thread *thread;
77170988 1633 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
bf2575c1 1634 struct syscall *sc = trace__syscall_info(trace, evsel, id);
2ae3a312
ACM
1635 struct thread_trace *ttrace;
1636
1637 if (sc == NULL)
1638 return -1;
ba3d7dee 1639
2ae3a312
ACM
1640 if (sc->filtered)
1641 return 0;
1642
8fb598e5 1643 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
c24ff998 1644 ttrace = thread__trace(thread, trace->output);
2ae3a312 1645 if (ttrace == NULL)
ba3d7dee
ACM
1646 return -1;
1647
bf2575c1
DA
1648 if (trace->summary)
1649 thread__update_stats(ttrace, id, sample);
1650
77170988 1651 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
ba3d7dee 1652
c522739d
ACM
1653 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1654 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1655 trace->last_vfs_getname = NULL;
1656 ++trace->stats.vfs_getname;
1657 }
1658
752fde44
ACM
1659 ttrace = thread->priv;
1660
1661 ttrace->exit_time = sample->time;
1662
ae9ed035 1663 if (ttrace->entry_time) {
60c907ab 1664 duration = sample->time - ttrace->entry_time;
ae9ed035
ACM
1665 if (trace__filter_duration(trace, duration))
1666 goto out;
1667 } else if (trace->duration_filter)
1668 goto out;
60c907ab 1669
fd2eabaf
DA
1670 if (trace->summary_only)
1671 goto out;
1672
c24ff998 1673 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
752fde44
ACM
1674
1675 if (ttrace->entry_pending) {
c24ff998 1676 fprintf(trace->output, "%-70s", ttrace->entry_str);
752fde44 1677 } else {
c24ff998
ACM
1678 fprintf(trace->output, " ... [");
1679 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1680 fprintf(trace->output, "]: %s()", sc->name);
752fde44
ACM
1681 }
1682
da3c9a44
ACM
1683 if (sc->fmt == NULL) {
1684signed_print:
1685 fprintf(trace->output, ") = %d", ret);
1686 } else if (ret < 0 && sc->fmt->errmsg) {
ba3d7dee
ACM
1687 char bf[256];
1688 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1689 *e = audit_errno_to_name(-ret);
1690
c24ff998 1691 fprintf(trace->output, ") = -1 %s %s", e, emsg);
da3c9a44 1692 } else if (ret == 0 && sc->fmt->timeout)
c24ff998 1693 fprintf(trace->output, ") = 0 Timeout");
04b34729
ACM
1694 else if (sc->fmt->hexret)
1695 fprintf(trace->output, ") = %#x", ret);
ba3d7dee 1696 else
da3c9a44 1697 goto signed_print;
ba3d7dee 1698
c24ff998 1699 fputc('\n', trace->output);
ae9ed035 1700out:
752fde44
ACM
1701 ttrace->entry_pending = false;
1702
ba3d7dee
ACM
1703 return 0;
1704}
1705
c522739d
ACM
1706static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1707 struct perf_sample *sample)
1708{
1709 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1710 return 0;
1711}
1712
1302d88e
ACM
1713static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1714 struct perf_sample *sample)
1715{
1716 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1717 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
8fb598e5 1718 struct thread *thread = machine__findnew_thread(trace->host,
314add6b
AH
1719 sample->pid,
1720 sample->tid);
c24ff998 1721 struct thread_trace *ttrace = thread__trace(thread, trace->output);
1302d88e
ACM
1722
1723 if (ttrace == NULL)
1724 goto out_dump;
1725
1726 ttrace->runtime_ms += runtime_ms;
1727 trace->runtime_ms += runtime_ms;
1728 return 0;
1729
1730out_dump:
c24ff998 1731 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
1302d88e
ACM
1732 evsel->name,
1733 perf_evsel__strval(evsel, sample, "comm"),
1734 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1735 runtime,
1736 perf_evsel__intval(evsel, sample, "vruntime"));
1737 return 0;
1738}
1739
bdc89661
DA
1740static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1741{
1742 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1743 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1744 return false;
1745
1746 if (trace->pid_list || trace->tid_list)
1747 return true;
1748
1749 return false;
1750}
1751
6810fc91
DA
1752static int trace__process_sample(struct perf_tool *tool,
1753 union perf_event *event __maybe_unused,
1754 struct perf_sample *sample,
1755 struct perf_evsel *evsel,
1756 struct machine *machine __maybe_unused)
1757{
1758 struct trace *trace = container_of(tool, struct trace, tool);
1759 int err = 0;
1760
744a9719 1761 tracepoint_handler handler = evsel->handler;
6810fc91 1762
bdc89661
DA
1763 if (skip_sample(trace, sample))
1764 return 0;
1765
4bb09192 1766 if (!trace->full_time && trace->base_time == 0)
6810fc91
DA
1767 trace->base_time = sample->time;
1768
3160565f
DA
1769 if (handler) {
1770 ++trace->nr_events;
6810fc91 1771 handler(trace, evsel, sample);
3160565f 1772 }
6810fc91
DA
1773
1774 return err;
1775}
1776
bdc89661
DA
1777static int parse_target_str(struct trace *trace)
1778{
1779 if (trace->opts.target.pid) {
1780 trace->pid_list = intlist__new(trace->opts.target.pid);
1781 if (trace->pid_list == NULL) {
1782 pr_err("Error parsing process id string\n");
1783 return -EINVAL;
1784 }
1785 }
1786
1787 if (trace->opts.target.tid) {
1788 trace->tid_list = intlist__new(trace->opts.target.tid);
1789 if (trace->tid_list == NULL) {
1790 pr_err("Error parsing thread id string\n");
1791 return -EINVAL;
1792 }
1793 }
1794
1795 return 0;
1796}
1797
5e2485b1
DA
1798static int trace__record(int argc, const char **argv)
1799{
1800 unsigned int rec_argc, i, j;
1801 const char **rec_argv;
1802 const char * const record_args[] = {
1803 "record",
1804 "-R",
1805 "-m", "1024",
1806 "-c", "1",
9aca7f17 1807 "-e",
5e2485b1
DA
1808 };
1809
9aca7f17
DA
1810 /* +1 is for the event string below */
1811 rec_argc = ARRAY_SIZE(record_args) + 1 + argc;
5e2485b1
DA
1812 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1813
1814 if (rec_argv == NULL)
1815 return -ENOMEM;
1816
1817 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1818 rec_argv[i] = record_args[i];
1819
9aca7f17
DA
1820 /* event string may be different for older kernels - e.g., RHEL6 */
1821 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
1822 rec_argv[i] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
1823 else if (is_valid_tracepoint("syscalls:sys_enter"))
1824 rec_argv[i] = "syscalls:sys_enter,syscalls:sys_exit";
1825 else {
1826 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
1827 return -1;
1828 }
1829 i++;
1830
5e2485b1
DA
1831 for (j = 0; j < (unsigned int)argc; j++, i++)
1832 rec_argv[i] = argv[j];
1833
1834 return cmd_record(i, rec_argv, NULL);
1835}
1836
bf2575c1
DA
1837static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
1838
c522739d
ACM
1839static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
1840{
ef503831 1841 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
c522739d
ACM
1842 if (evsel == NULL)
1843 return;
1844
1845 if (perf_evsel__field(evsel, "pathname") == NULL) {
1846 perf_evsel__delete(evsel);
1847 return;
1848 }
1849
744a9719 1850 evsel->handler = trace__vfs_getname;
c522739d
ACM
1851 perf_evlist__add(evlist, evsel);
1852}
1853
f15eb531 1854static int trace__run(struct trace *trace, int argc, const char **argv)
514f1c67 1855{
334fe7a3 1856 struct perf_evlist *evlist = perf_evlist__new();
ba3d7dee 1857 struct perf_evsel *evsel;
efd5745e
ACM
1858 int err = -1, i;
1859 unsigned long before;
f15eb531 1860 const bool forks = argc > 0;
514f1c67 1861
75b757ca
ACM
1862 trace->live = true;
1863
514f1c67 1864 if (evlist == NULL) {
c24ff998 1865 fprintf(trace->output, "Not enough memory to run!\n");
514f1c67
ACM
1866 goto out;
1867 }
1868
77170988 1869 if (perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, trace__sys_exit))
87f91868 1870 goto out_error_tp;
514f1c67 1871
c522739d
ACM
1872 perf_evlist__add_vfs_getname(evlist);
1873
1302d88e 1874 if (trace->sched &&
87f91868
RR
1875 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1876 trace__sched_stat_runtime))
1877 goto out_error_tp;
1302d88e 1878
514f1c67
ACM
1879 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1880 if (err < 0) {
c24ff998 1881 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
514f1c67
ACM
1882 goto out_delete_evlist;
1883 }
1884
752fde44
ACM
1885 err = trace__symbols_init(trace, evlist);
1886 if (err < 0) {
c24ff998 1887 fprintf(trace->output, "Problems initializing symbol libraries!\n");
03ad9747 1888 goto out_delete_evlist;
752fde44
ACM
1889 }
1890
f77a9518 1891 perf_evlist__config(evlist, &trace->opts);
514f1c67 1892
f15eb531
NK
1893 signal(SIGCHLD, sig_handler);
1894 signal(SIGINT, sig_handler);
1895
1896 if (forks) {
6ef73ec4 1897 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
735f7e0b 1898 argv, false, NULL);
f15eb531 1899 if (err < 0) {
c24ff998 1900 fprintf(trace->output, "Couldn't run the workload!\n");
03ad9747 1901 goto out_delete_evlist;
f15eb531
NK
1902 }
1903 }
1904
514f1c67 1905 err = perf_evlist__open(evlist);
a8f23d8f
ACM
1906 if (err < 0)
1907 goto out_error_open;
514f1c67 1908
f885037e 1909 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
514f1c67 1910 if (err < 0) {
c24ff998 1911 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
3beb0861 1912 goto out_close_evlist;
514f1c67
ACM
1913 }
1914
1915 perf_evlist__enable(evlist);
f15eb531
NK
1916
1917 if (forks)
1918 perf_evlist__start_workload(evlist);
1919
752fde44 1920 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
514f1c67 1921again:
efd5745e 1922 before = trace->nr_events;
514f1c67
ACM
1923
1924 for (i = 0; i < evlist->nr_mmaps; i++) {
1925 union perf_event *event;
1926
1927 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1928 const u32 type = event->header.type;
ba3d7dee 1929 tracepoint_handler handler;
514f1c67 1930 struct perf_sample sample;
514f1c67 1931
efd5745e 1932 ++trace->nr_events;
514f1c67 1933
514f1c67
ACM
1934 err = perf_evlist__parse_sample(evlist, event, &sample);
1935 if (err) {
c24ff998 1936 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
8e50d384 1937 goto next_event;
514f1c67
ACM
1938 }
1939
4bb09192 1940 if (!trace->full_time && trace->base_time == 0)
752fde44
ACM
1941 trace->base_time = sample.time;
1942
1943 if (type != PERF_RECORD_SAMPLE) {
162f0bef 1944 trace__process_event(trace, trace->host, event, &sample);
752fde44
ACM
1945 continue;
1946 }
1947
514f1c67
ACM
1948 evsel = perf_evlist__id2evsel(evlist, sample.id);
1949 if (evsel == NULL) {
c24ff998 1950 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
8e50d384 1951 goto next_event;
514f1c67
ACM
1952 }
1953
fc551f8d 1954 if (sample.raw_data == NULL) {
c24ff998 1955 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
fc551f8d
ACM
1956 perf_evsel__name(evsel), sample.tid,
1957 sample.cpu, sample.raw_size);
8e50d384 1958 goto next_event;
fc551f8d
ACM
1959 }
1960
744a9719 1961 handler = evsel->handler;
ba3d7dee 1962 handler(trace, evsel, &sample);
8e50d384
ZZ
1963next_event:
1964 perf_evlist__mmap_consume(evlist, i);
20c5f10e 1965
ba209f85
ACM
1966 if (interrupted)
1967 goto out_disable;
514f1c67
ACM
1968 }
1969 }
1970
efd5745e 1971 if (trace->nr_events == before) {
ba209f85 1972 int timeout = done ? 100 : -1;
f15eb531 1973
ba209f85
ACM
1974 if (poll(evlist->pollfd, evlist->nr_fds, timeout) > 0)
1975 goto again;
1976 } else {
1977 goto again;
f15eb531
NK
1978 }
1979
ba209f85
ACM
1980out_disable:
1981 perf_evlist__disable(evlist);
514f1c67 1982
c522739d
ACM
1983 if (!err) {
1984 if (trace->summary)
1985 trace__fprintf_thread_summary(trace, trace->output);
1986
1987 if (trace->show_tool_stats) {
1988 fprintf(trace->output, "Stats:\n "
1989 " vfs_getname : %" PRIu64 "\n"
1990 " proc_getname: %" PRIu64 "\n",
1991 trace->stats.vfs_getname,
1992 trace->stats.proc_getname);
1993 }
1994 }
bf2575c1 1995
3beb0861
NK
1996 perf_evlist__munmap(evlist);
1997out_close_evlist:
1998 perf_evlist__close(evlist);
514f1c67
ACM
1999out_delete_evlist:
2000 perf_evlist__delete(evlist);
2001out:
75b757ca 2002 trace->live = false;
514f1c67 2003 return err;
6ef068cb
ACM
2004{
2005 char errbuf[BUFSIZ];
a8f23d8f
ACM
2006
2007out_error_tp:
6ef068cb 2008 perf_evlist__strerror_tp(evlist, errno, errbuf, sizeof(errbuf));
a8f23d8f
ACM
2009 goto out_error;
2010
2011out_error_open:
2012 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2013
2014out_error:
6ef068cb 2015 fprintf(trace->output, "%s\n", errbuf);
87f91868 2016 goto out_delete_evlist;
514f1c67 2017}
a8f23d8f 2018}
514f1c67 2019
6810fc91
DA
2020static int trace__replay(struct trace *trace)
2021{
2022 const struct perf_evsel_str_handler handlers[] = {
c522739d 2023 { "probe:vfs_getname", trace__vfs_getname, },
6810fc91 2024 };
f5fc1412
JO
2025 struct perf_data_file file = {
2026 .path = input_name,
2027 .mode = PERF_DATA_MODE_READ,
2028 };
6810fc91 2029 struct perf_session *session;
003824e8 2030 struct perf_evsel *evsel;
6810fc91
DA
2031 int err = -1;
2032
2033 trace->tool.sample = trace__process_sample;
2034 trace->tool.mmap = perf_event__process_mmap;
384c671e 2035 trace->tool.mmap2 = perf_event__process_mmap2;
6810fc91
DA
2036 trace->tool.comm = perf_event__process_comm;
2037 trace->tool.exit = perf_event__process_exit;
2038 trace->tool.fork = perf_event__process_fork;
2039 trace->tool.attr = perf_event__process_attr;
2040 trace->tool.tracing_data = perf_event__process_tracing_data;
2041 trace->tool.build_id = perf_event__process_build_id;
2042
2043 trace->tool.ordered_samples = true;
2044 trace->tool.ordering_requires_timestamps = true;
2045
2046 /* add tid to output */
2047 trace->multiple_threads = true;
2048
2049 if (symbol__init() < 0)
2050 return -1;
2051
f5fc1412 2052 session = perf_session__new(&file, false, &trace->tool);
6810fc91
DA
2053 if (session == NULL)
2054 return -ENOMEM;
2055
8fb598e5
DA
2056 trace->host = &session->machines.host;
2057
6810fc91
DA
2058 err = perf_session__set_tracepoints_handlers(session, handlers);
2059 if (err)
2060 goto out;
2061
003824e8
NK
2062 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2063 "raw_syscalls:sys_enter");
9aca7f17
DA
2064 /* older kernels have syscalls tp versus raw_syscalls */
2065 if (evsel == NULL)
2066 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2067 "syscalls:sys_enter");
003824e8
NK
2068 if (evsel == NULL) {
2069 pr_err("Data file does not have raw_syscalls:sys_enter event\n");
2070 goto out;
2071 }
2072
2073 if (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2074 perf_evsel__init_sc_tp_ptr_field(evsel, args)) {
2075 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2076 goto out;
2077 }
2078
2079 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2080 "raw_syscalls:sys_exit");
9aca7f17
DA
2081 if (evsel == NULL)
2082 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2083 "syscalls:sys_exit");
003824e8
NK
2084 if (evsel == NULL) {
2085 pr_err("Data file does not have raw_syscalls:sys_exit event\n");
6810fc91
DA
2086 goto out;
2087 }
2088
003824e8
NK
2089 if (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2090 perf_evsel__init_sc_tp_uint_field(evsel, ret)) {
2091 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
6810fc91
DA
2092 goto out;
2093 }
2094
bdc89661
DA
2095 err = parse_target_str(trace);
2096 if (err != 0)
2097 goto out;
2098
6810fc91
DA
2099 setup_pager();
2100
2101 err = perf_session__process_events(session, &trace->tool);
2102 if (err)
2103 pr_err("Failed to process events, error %d", err);
2104
bf2575c1
DA
2105 else if (trace->summary)
2106 trace__fprintf_thread_summary(trace, trace->output);
2107
6810fc91
DA
2108out:
2109 perf_session__delete(session);
2110
2111 return err;
2112}
2113
1302d88e
ACM
2114static size_t trace__fprintf_threads_header(FILE *fp)
2115{
2116 size_t printed;
2117
99ff7150 2118 printed = fprintf(fp, "\n Summary of events:\n\n");
bf2575c1
DA
2119
2120 return printed;
2121}
2122
2123static size_t thread__dump_stats(struct thread_trace *ttrace,
2124 struct trace *trace, FILE *fp)
2125{
2126 struct stats *stats;
2127 size_t printed = 0;
2128 struct syscall *sc;
2129 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2130
2131 if (inode == NULL)
2132 return 0;
2133
2134 printed += fprintf(fp, "\n");
2135
27a778b5
PE
2136 printed += fprintf(fp, " syscall calls min avg max stddev\n");
2137 printed += fprintf(fp, " (msec) (msec) (msec) (%%)\n");
2138 printed += fprintf(fp, " --------------- -------- --------- --------- --------- ------\n");
99ff7150 2139
bf2575c1
DA
2140 /* each int_node is a syscall */
2141 while (inode) {
2142 stats = inode->priv;
2143 if (stats) {
2144 double min = (double)(stats->min) / NSEC_PER_MSEC;
2145 double max = (double)(stats->max) / NSEC_PER_MSEC;
2146 double avg = avg_stats(stats);
2147 double pct;
2148 u64 n = (u64) stats->n;
2149
2150 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2151 avg /= NSEC_PER_MSEC;
2152
2153 sc = &trace->syscalls.table[inode->i];
99ff7150 2154 printed += fprintf(fp, " %-15s", sc->name);
27a778b5 2155 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f",
7f7a4138 2156 n, min, avg);
27a778b5 2157 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
bf2575c1
DA
2158 }
2159
2160 inode = intlist__next(inode);
2161 }
2162
2163 printed += fprintf(fp, "\n\n");
1302d88e
ACM
2164
2165 return printed;
2166}
2167
896cbb56
DA
2168/* struct used to pass data to per-thread function */
2169struct summary_data {
2170 FILE *fp;
2171 struct trace *trace;
2172 size_t printed;
2173};
2174
2175static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2176{
2177 struct summary_data *data = priv;
2178 FILE *fp = data->fp;
2179 size_t printed = data->printed;
2180 struct trace *trace = data->trace;
2181 struct thread_trace *ttrace = thread->priv;
896cbb56
DA
2182 double ratio;
2183
2184 if (ttrace == NULL)
2185 return 0;
2186
2187 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2188
15e65c69 2189 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
99ff7150 2190 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
15e65c69 2191 printed += fprintf(fp, "%.1f%%", ratio);
99ff7150 2192 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
bf2575c1 2193 printed += thread__dump_stats(ttrace, trace, fp);
896cbb56
DA
2194
2195 data->printed += printed;
2196
2197 return 0;
2198}
2199
1302d88e
ACM
2200static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2201{
896cbb56
DA
2202 struct summary_data data = {
2203 .fp = fp,
2204 .trace = trace
2205 };
2206 data.printed = trace__fprintf_threads_header(fp);
1302d88e 2207
896cbb56
DA
2208 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
2209
2210 return data.printed;
1302d88e
ACM
2211}
2212
ae9ed035
ACM
2213static int trace__set_duration(const struct option *opt, const char *str,
2214 int unset __maybe_unused)
2215{
2216 struct trace *trace = opt->value;
2217
2218 trace->duration_filter = atof(str);
2219 return 0;
2220}
2221
c24ff998
ACM
2222static int trace__open_output(struct trace *trace, const char *filename)
2223{
2224 struct stat st;
2225
2226 if (!stat(filename, &st) && st.st_size) {
2227 char oldname[PATH_MAX];
2228
2229 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2230 unlink(oldname);
2231 rename(filename, oldname);
2232 }
2233
2234 trace->output = fopen(filename, "w");
2235
2236 return trace->output == NULL ? -errno : 0;
2237}
2238
514f1c67
ACM
2239int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2240{
2241 const char * const trace_usage[] = {
f15eb531
NK
2242 "perf trace [<options>] [<command>]",
2243 "perf trace [<options>] -- <command> [<options>]",
5e2485b1
DA
2244 "perf trace record [<options>] [<command>]",
2245 "perf trace record [<options>] -- <command> [<options>]",
514f1c67
ACM
2246 NULL
2247 };
2248 struct trace trace = {
c522739d
ACM
2249 .audit = {
2250 .machine = audit_detect_machine(),
2251 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2252 },
514f1c67
ACM
2253 .syscalls = {
2254 . max = -1,
2255 },
2256 .opts = {
2257 .target = {
2258 .uid = UINT_MAX,
2259 .uses_mmap = true,
2260 },
2261 .user_freq = UINT_MAX,
2262 .user_interval = ULLONG_MAX,
2263 .no_delay = true,
2264 .mmap_pages = 1024,
2265 },
c24ff998 2266 .output = stdout,
50c95cbd 2267 .show_comm = true,
514f1c67 2268 };
c24ff998 2269 const char *output_name = NULL;
2ae3a312 2270 const char *ev_qualifier_str = NULL;
514f1c67 2271 const struct option trace_options[] = {
50c95cbd
ACM
2272 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2273 "show the thread COMM next to its id"),
c522739d 2274 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
2ae3a312
ACM
2275 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
2276 "list of events to trace"),
c24ff998 2277 OPT_STRING('o', "output", &output_name, "file", "output file name"),
6810fc91 2278 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
514f1c67
ACM
2279 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2280 "trace events on existing process id"),
ac9be8ee 2281 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
514f1c67 2282 "trace events on existing thread id"),
ac9be8ee 2283 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
514f1c67 2284 "system-wide collection from all CPUs"),
ac9be8ee 2285 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
514f1c67 2286 "list of cpus to monitor"),
6810fc91 2287 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
514f1c67 2288 "child tasks do not inherit counters"),
994a1f78
JO
2289 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2290 "number of mmap data pages",
2291 perf_evlist__parse_mmap_pages),
ac9be8ee 2292 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
514f1c67 2293 "user to profile"),
ae9ed035
ACM
2294 OPT_CALLBACK(0, "duration", &trace, "float",
2295 "show only events with duration > N.M ms",
2296 trace__set_duration),
1302d88e 2297 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
7c304ee0 2298 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
4bb09192
DA
2299 OPT_BOOLEAN('T', "time", &trace.full_time,
2300 "Show full timestamp, not time relative to first start"),
fd2eabaf
DA
2301 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2302 "Show only syscall summary with statistics"),
2303 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2304 "Show all syscalls and summary with statistics"),
514f1c67
ACM
2305 OPT_END()
2306 };
2307 int err;
32caf0d1 2308 char bf[BUFSIZ];
514f1c67 2309
5e2485b1
DA
2310 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
2311 return trace__record(argc-2, &argv[2]);
2312
514f1c67 2313 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
514f1c67 2314
fd2eabaf
DA
2315 /* summary_only implies summary option, but don't overwrite summary if set */
2316 if (trace.summary_only)
2317 trace.summary = trace.summary_only;
2318
c24ff998
ACM
2319 if (output_name != NULL) {
2320 err = trace__open_output(&trace, output_name);
2321 if (err < 0) {
2322 perror("failed to create output file");
2323 goto out;
2324 }
2325 }
2326
2ae3a312 2327 if (ev_qualifier_str != NULL) {
b059efdf
ACM
2328 const char *s = ev_qualifier_str;
2329
2330 trace.not_ev_qualifier = *s == '!';
2331 if (trace.not_ev_qualifier)
2332 ++s;
2333 trace.ev_qualifier = strlist__new(true, s);
2ae3a312 2334 if (trace.ev_qualifier == NULL) {
c24ff998
ACM
2335 fputs("Not enough memory to parse event qualifier",
2336 trace.output);
2337 err = -ENOMEM;
2338 goto out_close;
2ae3a312
ACM
2339 }
2340 }
2341
602ad878 2342 err = target__validate(&trace.opts.target);
32caf0d1 2343 if (err) {
602ad878 2344 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
2345 fprintf(trace.output, "%s", bf);
2346 goto out_close;
32caf0d1
NK
2347 }
2348
602ad878 2349 err = target__parse_uid(&trace.opts.target);
514f1c67 2350 if (err) {
602ad878 2351 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
2352 fprintf(trace.output, "%s", bf);
2353 goto out_close;
514f1c67
ACM
2354 }
2355
602ad878 2356 if (!argc && target__none(&trace.opts.target))
ee76120e
NK
2357 trace.opts.target.system_wide = true;
2358
6810fc91
DA
2359 if (input_name)
2360 err = trace__replay(&trace);
2361 else
2362 err = trace__run(&trace, argc, argv);
1302d88e 2363
c24ff998
ACM
2364out_close:
2365 if (output_name != NULL)
2366 fclose(trace.output);
2367out:
1302d88e 2368 return err;
514f1c67 2369}