]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - tools/perf/builtin-trace.c
perf list: Fix checking for supported events on older kernels
[mirror_ubuntu-artful-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;
c24ff998 1163 FILE *output;
efd5745e 1164 unsigned long nr_events;
b059efdf 1165 struct strlist *ev_qualifier;
c522739d 1166 const char *last_vfs_getname;
bdc89661
DA
1167 struct intlist *tid_list;
1168 struct intlist *pid_list;
98eafce6
ACM
1169 double duration_filter;
1170 double runtime_ms;
1171 struct {
1172 u64 vfs_getname,
1173 proc_getname;
1174 } stats;
1175 bool not_ev_qualifier;
1176 bool live;
1177 bool full_time;
1302d88e 1178 bool sched;
752fde44 1179 bool multiple_threads;
bf2575c1 1180 bool summary;
fd2eabaf 1181 bool summary_only;
50c95cbd 1182 bool show_comm;
c522739d 1183 bool show_tool_stats;
514f1c67
ACM
1184};
1185
97119f37 1186static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
75b757ca
ACM
1187{
1188 struct thread_trace *ttrace = thread->priv;
75b757ca
ACM
1189
1190 if (fd > ttrace->paths.max) {
1191 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1192
1193 if (npath == NULL)
1194 return -1;
1195
1196 if (ttrace->paths.max != -1) {
1197 memset(npath + ttrace->paths.max + 1, 0,
1198 (fd - ttrace->paths.max) * sizeof(char *));
1199 } else {
1200 memset(npath, 0, (fd + 1) * sizeof(char *));
1201 }
1202
1203 ttrace->paths.table = npath;
1204 ttrace->paths.max = fd;
1205 }
1206
1207 ttrace->paths.table[fd] = strdup(pathname);
1208
1209 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1210}
1211
97119f37
ACM
1212static int thread__read_fd_path(struct thread *thread, int fd)
1213{
1214 char linkname[PATH_MAX], pathname[PATH_MAX];
1215 struct stat st;
1216 int ret;
1217
1218 if (thread->pid_ == thread->tid) {
1219 scnprintf(linkname, sizeof(linkname),
1220 "/proc/%d/fd/%d", thread->pid_, fd);
1221 } else {
1222 scnprintf(linkname, sizeof(linkname),
1223 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1224 }
1225
1226 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1227 return -1;
1228
1229 ret = readlink(linkname, pathname, sizeof(pathname));
1230
1231 if (ret < 0 || ret > st.st_size)
1232 return -1;
1233
1234 pathname[ret] = '\0';
1235 return trace__set_fd_pathname(thread, fd, pathname);
1236}
1237
c522739d
ACM
1238static const char *thread__fd_path(struct thread *thread, int fd,
1239 struct trace *trace)
75b757ca
ACM
1240{
1241 struct thread_trace *ttrace = thread->priv;
1242
1243 if (ttrace == NULL)
1244 return NULL;
1245
1246 if (fd < 0)
1247 return NULL;
1248
c522739d
ACM
1249 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL))
1250 if (!trace->live)
1251 return NULL;
1252 ++trace->stats.proc_getname;
1253 if (thread__read_fd_path(thread, fd)) {
1254 return NULL;
1255 }
75b757ca
ACM
1256
1257 return ttrace->paths.table[fd];
1258}
1259
1260static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1261 struct syscall_arg *arg)
1262{
1263 int fd = arg->val;
1264 size_t printed = scnprintf(bf, size, "%d", fd);
c522739d 1265 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
75b757ca
ACM
1266
1267 if (path)
1268 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1269
1270 return printed;
1271}
1272
1273static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1274 struct syscall_arg *arg)
1275{
1276 int fd = arg->val;
1277 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1278 struct thread_trace *ttrace = arg->thread->priv;
1279
04662523
ACM
1280 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1281 zfree(&ttrace->paths.table[fd]);
75b757ca
ACM
1282
1283 return printed;
1284}
1285
ae9ed035
ACM
1286static bool trace__filter_duration(struct trace *trace, double t)
1287{
1288 return t < (trace->duration_filter * NSEC_PER_MSEC);
1289}
1290
752fde44
ACM
1291static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1292{
1293 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1294
60c907ab 1295 return fprintf(fp, "%10.3f ", ts);
752fde44
ACM
1296}
1297
f15eb531 1298static bool done = false;
ba209f85 1299static bool interrupted = false;
f15eb531 1300
ba209f85 1301static void sig_handler(int sig)
f15eb531
NK
1302{
1303 done = true;
ba209f85 1304 interrupted = sig == SIGINT;
f15eb531
NK
1305}
1306
752fde44 1307static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
60c907ab 1308 u64 duration, u64 tstamp, FILE *fp)
752fde44
ACM
1309{
1310 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
60c907ab 1311 printed += fprintf_duration(duration, fp);
752fde44 1312
50c95cbd
ACM
1313 if (trace->multiple_threads) {
1314 if (trace->show_comm)
1902efe7 1315 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
38051234 1316 printed += fprintf(fp, "%d ", thread->tid);
50c95cbd 1317 }
752fde44
ACM
1318
1319 return printed;
1320}
1321
c24ff998 1322static int trace__process_event(struct trace *trace, struct machine *machine,
162f0bef 1323 union perf_event *event, struct perf_sample *sample)
752fde44
ACM
1324{
1325 int ret = 0;
1326
1327 switch (event->header.type) {
1328 case PERF_RECORD_LOST:
c24ff998 1329 color_fprintf(trace->output, PERF_COLOR_RED,
752fde44 1330 "LOST %" PRIu64 " events!\n", event->lost.lost);
162f0bef 1331 ret = machine__process_lost_event(machine, event, sample);
752fde44 1332 default:
162f0bef 1333 ret = machine__process_event(machine, event, sample);
752fde44
ACM
1334 break;
1335 }
1336
1337 return ret;
1338}
1339
c24ff998 1340static int trace__tool_process(struct perf_tool *tool,
752fde44 1341 union perf_event *event,
162f0bef 1342 struct perf_sample *sample,
752fde44
ACM
1343 struct machine *machine)
1344{
c24ff998 1345 struct trace *trace = container_of(tool, struct trace, tool);
162f0bef 1346 return trace__process_event(trace, machine, event, sample);
752fde44
ACM
1347}
1348
1349static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1350{
1351 int err = symbol__init();
1352
1353 if (err)
1354 return err;
1355
8fb598e5
DA
1356 trace->host = machine__new_host();
1357 if (trace->host == NULL)
1358 return -ENOMEM;
752fde44 1359
a33fbd56
ACM
1360 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
1361 evlist->threads, trace__tool_process, false);
752fde44
ACM
1362 if (err)
1363 symbol__exit();
1364
1365 return err;
1366}
1367
13d4ff3e
ACM
1368static int syscall__set_arg_fmts(struct syscall *sc)
1369{
1370 struct format_field *field;
1371 int idx = 0;
1372
1373 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1374 if (sc->arg_scnprintf == NULL)
1375 return -1;
1376
1f115cb7
ACM
1377 if (sc->fmt)
1378 sc->arg_parm = sc->fmt->arg_parm;
1379
13d4ff3e 1380 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
beccb2b5
ACM
1381 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1382 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1383 else if (field->flags & FIELD_IS_POINTER)
13d4ff3e
ACM
1384 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1385 ++idx;
1386 }
1387
1388 return 0;
1389}
1390
514f1c67
ACM
1391static int trace__read_syscall_info(struct trace *trace, int id)
1392{
1393 char tp_name[128];
1394 struct syscall *sc;
c522739d 1395 const char *name = audit_syscall_to_name(id, trace->audit.machine);
3a531260
ACM
1396
1397 if (name == NULL)
1398 return -1;
514f1c67
ACM
1399
1400 if (id > trace->syscalls.max) {
1401 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1402
1403 if (nsyscalls == NULL)
1404 return -1;
1405
1406 if (trace->syscalls.max != -1) {
1407 memset(nsyscalls + trace->syscalls.max + 1, 0,
1408 (id - trace->syscalls.max) * sizeof(*sc));
1409 } else {
1410 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1411 }
1412
1413 trace->syscalls.table = nsyscalls;
1414 trace->syscalls.max = id;
1415 }
1416
1417 sc = trace->syscalls.table + id;
3a531260 1418 sc->name = name;
2ae3a312 1419
b059efdf
ACM
1420 if (trace->ev_qualifier) {
1421 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1422
1423 if (!(in ^ trace->not_ev_qualifier)) {
1424 sc->filtered = true;
1425 /*
1426 * No need to do read tracepoint information since this will be
1427 * filtered out.
1428 */
1429 return 0;
1430 }
2ae3a312
ACM
1431 }
1432
3a531260 1433 sc->fmt = syscall_fmt__find(sc->name);
514f1c67 1434
aec1930b 1435 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
97978b3e 1436 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
aec1930b
ACM
1437
1438 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1439 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
97978b3e 1440 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
aec1930b 1441 }
514f1c67 1442
13d4ff3e
ACM
1443 if (sc->tp_format == NULL)
1444 return -1;
1445
1446 return syscall__set_arg_fmts(sc);
514f1c67
ACM
1447}
1448
752fde44 1449static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
75b757ca
ACM
1450 unsigned long *args, struct trace *trace,
1451 struct thread *thread)
514f1c67 1452{
514f1c67
ACM
1453 size_t printed = 0;
1454
1455 if (sc->tp_format != NULL) {
1456 struct format_field *field;
01533e97
ACM
1457 u8 bit = 1;
1458 struct syscall_arg arg = {
75b757ca
ACM
1459 .idx = 0,
1460 .mask = 0,
1461 .trace = trace,
1462 .thread = thread,
01533e97 1463 };
6e7eeb51
ACM
1464
1465 for (field = sc->tp_format->format.fields->next; field;
01533e97
ACM
1466 field = field->next, ++arg.idx, bit <<= 1) {
1467 if (arg.mask & bit)
6e7eeb51 1468 continue;
4aa58232
ACM
1469 /*
1470 * Suppress this argument if its value is zero and
1471 * and we don't have a string associated in an
1472 * strarray for it.
1473 */
1474 if (args[arg.idx] == 0 &&
1475 !(sc->arg_scnprintf &&
1476 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1477 sc->arg_parm[arg.idx]))
22ae5cf1
ACM
1478 continue;
1479
752fde44 1480 printed += scnprintf(bf + printed, size - printed,
13d4ff3e 1481 "%s%s: ", printed ? ", " : "", field->name);
01533e97
ACM
1482 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1483 arg.val = args[arg.idx];
1f115cb7
ACM
1484 if (sc->arg_parm)
1485 arg.parm = sc->arg_parm[arg.idx];
01533e97
ACM
1486 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1487 size - printed, &arg);
6e7eeb51 1488 } else {
13d4ff3e 1489 printed += scnprintf(bf + printed, size - printed,
01533e97 1490 "%ld", args[arg.idx]);
6e7eeb51 1491 }
514f1c67
ACM
1492 }
1493 } else {
01533e97
ACM
1494 int i = 0;
1495
514f1c67 1496 while (i < 6) {
752fde44
ACM
1497 printed += scnprintf(bf + printed, size - printed,
1498 "%sarg%d: %ld",
1499 printed ? ", " : "", i, args[i]);
514f1c67
ACM
1500 ++i;
1501 }
1502 }
1503
1504 return printed;
1505}
1506
ba3d7dee
ACM
1507typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1508 struct perf_sample *sample);
1509
1510static struct syscall *trace__syscall_info(struct trace *trace,
bf2575c1 1511 struct perf_evsel *evsel, int id)
ba3d7dee 1512{
ba3d7dee
ACM
1513
1514 if (id < 0) {
adaa18bf
ACM
1515
1516 /*
1517 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1518 * before that, leaving at a higher verbosity level till that is
1519 * explained. Reproduced with plain ftrace with:
1520 *
1521 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1522 * grep "NR -1 " /t/trace_pipe
1523 *
1524 * After generating some load on the machine.
1525 */
1526 if (verbose > 1) {
1527 static u64 n;
1528 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1529 id, perf_evsel__name(evsel), ++n);
1530 }
ba3d7dee
ACM
1531 return NULL;
1532 }
1533
1534 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1535 trace__read_syscall_info(trace, id))
1536 goto out_cant_read;
1537
1538 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1539 goto out_cant_read;
1540
1541 return &trace->syscalls.table[id];
1542
1543out_cant_read:
7c304ee0
ACM
1544 if (verbose) {
1545 fprintf(trace->output, "Problems reading syscall %d", id);
1546 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1547 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1548 fputs(" information\n", trace->output);
1549 }
ba3d7dee
ACM
1550 return NULL;
1551}
1552
bf2575c1
DA
1553static void thread__update_stats(struct thread_trace *ttrace,
1554 int id, struct perf_sample *sample)
1555{
1556 struct int_node *inode;
1557 struct stats *stats;
1558 u64 duration = 0;
1559
1560 inode = intlist__findnew(ttrace->syscall_stats, id);
1561 if (inode == NULL)
1562 return;
1563
1564 stats = inode->priv;
1565 if (stats == NULL) {
1566 stats = malloc(sizeof(struct stats));
1567 if (stats == NULL)
1568 return;
1569 init_stats(stats);
1570 inode->priv = stats;
1571 }
1572
1573 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1574 duration = sample->time - ttrace->entry_time;
1575
1576 update_stats(stats, duration);
1577}
1578
ba3d7dee
ACM
1579static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1580 struct perf_sample *sample)
1581{
752fde44 1582 char *msg;
ba3d7dee 1583 void *args;
752fde44 1584 size_t printed = 0;
2ae3a312 1585 struct thread *thread;
77170988 1586 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
bf2575c1 1587 struct syscall *sc = trace__syscall_info(trace, evsel, id);
2ae3a312
ACM
1588 struct thread_trace *ttrace;
1589
1590 if (sc == NULL)
1591 return -1;
ba3d7dee 1592
2ae3a312
ACM
1593 if (sc->filtered)
1594 return 0;
1595
8fb598e5 1596 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
c24ff998 1597 ttrace = thread__trace(thread, trace->output);
2ae3a312 1598 if (ttrace == NULL)
ba3d7dee
ACM
1599 return -1;
1600
77170988 1601 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
752fde44
ACM
1602 ttrace = thread->priv;
1603
1604 if (ttrace->entry_str == NULL) {
1605 ttrace->entry_str = malloc(1024);
1606 if (!ttrace->entry_str)
1607 return -1;
1608 }
1609
1610 ttrace->entry_time = sample->time;
1611 msg = ttrace->entry_str;
1612 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1613
75b757ca
ACM
1614 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1615 args, trace, thread);
752fde44
ACM
1616
1617 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
fd2eabaf 1618 if (!trace->duration_filter && !trace->summary_only) {
c24ff998
ACM
1619 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1620 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
ae9ed035 1621 }
752fde44
ACM
1622 } else
1623 ttrace->entry_pending = true;
ba3d7dee
ACM
1624
1625 return 0;
1626}
1627
1628static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1629 struct perf_sample *sample)
1630{
1631 int ret;
60c907ab 1632 u64 duration = 0;
2ae3a312 1633 struct thread *thread;
77170988 1634 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
bf2575c1 1635 struct syscall *sc = trace__syscall_info(trace, evsel, id);
2ae3a312
ACM
1636 struct thread_trace *ttrace;
1637
1638 if (sc == NULL)
1639 return -1;
ba3d7dee 1640
2ae3a312
ACM
1641 if (sc->filtered)
1642 return 0;
1643
8fb598e5 1644 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
c24ff998 1645 ttrace = thread__trace(thread, trace->output);
2ae3a312 1646 if (ttrace == NULL)
ba3d7dee
ACM
1647 return -1;
1648
bf2575c1
DA
1649 if (trace->summary)
1650 thread__update_stats(ttrace, id, sample);
1651
77170988 1652 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
ba3d7dee 1653
c522739d
ACM
1654 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1655 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1656 trace->last_vfs_getname = NULL;
1657 ++trace->stats.vfs_getname;
1658 }
1659
752fde44
ACM
1660 ttrace = thread->priv;
1661
1662 ttrace->exit_time = sample->time;
1663
ae9ed035 1664 if (ttrace->entry_time) {
60c907ab 1665 duration = sample->time - ttrace->entry_time;
ae9ed035
ACM
1666 if (trace__filter_duration(trace, duration))
1667 goto out;
1668 } else if (trace->duration_filter)
1669 goto out;
60c907ab 1670
fd2eabaf
DA
1671 if (trace->summary_only)
1672 goto out;
1673
c24ff998 1674 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
752fde44
ACM
1675
1676 if (ttrace->entry_pending) {
c24ff998 1677 fprintf(trace->output, "%-70s", ttrace->entry_str);
752fde44 1678 } else {
c24ff998
ACM
1679 fprintf(trace->output, " ... [");
1680 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1681 fprintf(trace->output, "]: %s()", sc->name);
752fde44
ACM
1682 }
1683
da3c9a44
ACM
1684 if (sc->fmt == NULL) {
1685signed_print:
1686 fprintf(trace->output, ") = %d", ret);
1687 } else if (ret < 0 && sc->fmt->errmsg) {
ba3d7dee
ACM
1688 char bf[256];
1689 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1690 *e = audit_errno_to_name(-ret);
1691
c24ff998 1692 fprintf(trace->output, ") = -1 %s %s", e, emsg);
da3c9a44 1693 } else if (ret == 0 && sc->fmt->timeout)
c24ff998 1694 fprintf(trace->output, ") = 0 Timeout");
04b34729
ACM
1695 else if (sc->fmt->hexret)
1696 fprintf(trace->output, ") = %#x", ret);
ba3d7dee 1697 else
da3c9a44 1698 goto signed_print;
ba3d7dee 1699
c24ff998 1700 fputc('\n', trace->output);
ae9ed035 1701out:
752fde44
ACM
1702 ttrace->entry_pending = false;
1703
ba3d7dee
ACM
1704 return 0;
1705}
1706
c522739d
ACM
1707static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1708 struct perf_sample *sample)
1709{
1710 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1711 return 0;
1712}
1713
1302d88e
ACM
1714static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1715 struct perf_sample *sample)
1716{
1717 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1718 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
8fb598e5 1719 struct thread *thread = machine__findnew_thread(trace->host,
314add6b
AH
1720 sample->pid,
1721 sample->tid);
c24ff998 1722 struct thread_trace *ttrace = thread__trace(thread, trace->output);
1302d88e
ACM
1723
1724 if (ttrace == NULL)
1725 goto out_dump;
1726
1727 ttrace->runtime_ms += runtime_ms;
1728 trace->runtime_ms += runtime_ms;
1729 return 0;
1730
1731out_dump:
c24ff998 1732 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
1302d88e
ACM
1733 evsel->name,
1734 perf_evsel__strval(evsel, sample, "comm"),
1735 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1736 runtime,
1737 perf_evsel__intval(evsel, sample, "vruntime"));
1738 return 0;
1739}
1740
bdc89661
DA
1741static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1742{
1743 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1744 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1745 return false;
1746
1747 if (trace->pid_list || trace->tid_list)
1748 return true;
1749
1750 return false;
1751}
1752
6810fc91
DA
1753static int trace__process_sample(struct perf_tool *tool,
1754 union perf_event *event __maybe_unused,
1755 struct perf_sample *sample,
1756 struct perf_evsel *evsel,
1757 struct machine *machine __maybe_unused)
1758{
1759 struct trace *trace = container_of(tool, struct trace, tool);
1760 int err = 0;
1761
744a9719 1762 tracepoint_handler handler = evsel->handler;
6810fc91 1763
bdc89661
DA
1764 if (skip_sample(trace, sample))
1765 return 0;
1766
4bb09192 1767 if (!trace->full_time && trace->base_time == 0)
6810fc91
DA
1768 trace->base_time = sample->time;
1769
3160565f
DA
1770 if (handler) {
1771 ++trace->nr_events;
6810fc91 1772 handler(trace, evsel, sample);
3160565f 1773 }
6810fc91
DA
1774
1775 return err;
1776}
1777
bdc89661
DA
1778static int parse_target_str(struct trace *trace)
1779{
1780 if (trace->opts.target.pid) {
1781 trace->pid_list = intlist__new(trace->opts.target.pid);
1782 if (trace->pid_list == NULL) {
1783 pr_err("Error parsing process id string\n");
1784 return -EINVAL;
1785 }
1786 }
1787
1788 if (trace->opts.target.tid) {
1789 trace->tid_list = intlist__new(trace->opts.target.tid);
1790 if (trace->tid_list == NULL) {
1791 pr_err("Error parsing thread id string\n");
1792 return -EINVAL;
1793 }
1794 }
1795
1796 return 0;
1797}
1798
5e2485b1
DA
1799static int trace__record(int argc, const char **argv)
1800{
1801 unsigned int rec_argc, i, j;
1802 const char **rec_argv;
1803 const char * const record_args[] = {
1804 "record",
1805 "-R",
1806 "-m", "1024",
1807 "-c", "1",
9aca7f17 1808 "-e",
5e2485b1
DA
1809 };
1810
9aca7f17
DA
1811 /* +1 is for the event string below */
1812 rec_argc = ARRAY_SIZE(record_args) + 1 + argc;
5e2485b1
DA
1813 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1814
1815 if (rec_argv == NULL)
1816 return -ENOMEM;
1817
1818 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1819 rec_argv[i] = record_args[i];
1820
9aca7f17
DA
1821 /* event string may be different for older kernels - e.g., RHEL6 */
1822 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
1823 rec_argv[i] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
1824 else if (is_valid_tracepoint("syscalls:sys_enter"))
1825 rec_argv[i] = "syscalls:sys_enter,syscalls:sys_exit";
1826 else {
1827 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
1828 return -1;
1829 }
1830 i++;
1831
5e2485b1
DA
1832 for (j = 0; j < (unsigned int)argc; j++, i++)
1833 rec_argv[i] = argv[j];
1834
1835 return cmd_record(i, rec_argv, NULL);
1836}
1837
bf2575c1
DA
1838static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
1839
c522739d
ACM
1840static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
1841{
ef503831 1842 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
c522739d
ACM
1843 if (evsel == NULL)
1844 return;
1845
1846 if (perf_evsel__field(evsel, "pathname") == NULL) {
1847 perf_evsel__delete(evsel);
1848 return;
1849 }
1850
744a9719 1851 evsel->handler = trace__vfs_getname;
c522739d
ACM
1852 perf_evlist__add(evlist, evsel);
1853}
1854
f15eb531 1855static int trace__run(struct trace *trace, int argc, const char **argv)
514f1c67 1856{
334fe7a3 1857 struct perf_evlist *evlist = perf_evlist__new();
ba3d7dee 1858 struct perf_evsel *evsel;
efd5745e
ACM
1859 int err = -1, i;
1860 unsigned long before;
f15eb531 1861 const bool forks = argc > 0;
514f1c67 1862
75b757ca
ACM
1863 trace->live = true;
1864
514f1c67 1865 if (evlist == NULL) {
c24ff998 1866 fprintf(trace->output, "Not enough memory to run!\n");
514f1c67
ACM
1867 goto out;
1868 }
1869
77170988 1870 if (perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, trace__sys_exit))
87f91868 1871 goto out_error_tp;
514f1c67 1872
c522739d
ACM
1873 perf_evlist__add_vfs_getname(evlist);
1874
1302d88e 1875 if (trace->sched &&
87f91868
RR
1876 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1877 trace__sched_stat_runtime))
1878 goto out_error_tp;
1302d88e 1879
514f1c67
ACM
1880 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1881 if (err < 0) {
c24ff998 1882 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
514f1c67
ACM
1883 goto out_delete_evlist;
1884 }
1885
752fde44
ACM
1886 err = trace__symbols_init(trace, evlist);
1887 if (err < 0) {
c24ff998 1888 fprintf(trace->output, "Problems initializing symbol libraries!\n");
03ad9747 1889 goto out_delete_evlist;
752fde44
ACM
1890 }
1891
f77a9518 1892 perf_evlist__config(evlist, &trace->opts);
514f1c67 1893
f15eb531
NK
1894 signal(SIGCHLD, sig_handler);
1895 signal(SIGINT, sig_handler);
1896
1897 if (forks) {
6ef73ec4 1898 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
735f7e0b 1899 argv, false, NULL);
f15eb531 1900 if (err < 0) {
c24ff998 1901 fprintf(trace->output, "Couldn't run the workload!\n");
03ad9747 1902 goto out_delete_evlist;
f15eb531
NK
1903 }
1904 }
1905
514f1c67 1906 err = perf_evlist__open(evlist);
a8f23d8f
ACM
1907 if (err < 0)
1908 goto out_error_open;
514f1c67 1909
f885037e 1910 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
514f1c67 1911 if (err < 0) {
c24ff998 1912 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
f26e1c7c 1913 goto out_delete_evlist;
514f1c67
ACM
1914 }
1915
1916 perf_evlist__enable(evlist);
f15eb531
NK
1917
1918 if (forks)
1919 perf_evlist__start_workload(evlist);
1920
752fde44 1921 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
514f1c67 1922again:
efd5745e 1923 before = trace->nr_events;
514f1c67
ACM
1924
1925 for (i = 0; i < evlist->nr_mmaps; i++) {
1926 union perf_event *event;
1927
1928 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1929 const u32 type = event->header.type;
ba3d7dee 1930 tracepoint_handler handler;
514f1c67 1931 struct perf_sample sample;
514f1c67 1932
efd5745e 1933 ++trace->nr_events;
514f1c67 1934
514f1c67
ACM
1935 err = perf_evlist__parse_sample(evlist, event, &sample);
1936 if (err) {
c24ff998 1937 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
8e50d384 1938 goto next_event;
514f1c67
ACM
1939 }
1940
4bb09192 1941 if (!trace->full_time && trace->base_time == 0)
752fde44
ACM
1942 trace->base_time = sample.time;
1943
1944 if (type != PERF_RECORD_SAMPLE) {
162f0bef 1945 trace__process_event(trace, trace->host, event, &sample);
752fde44
ACM
1946 continue;
1947 }
1948
514f1c67
ACM
1949 evsel = perf_evlist__id2evsel(evlist, sample.id);
1950 if (evsel == NULL) {
c24ff998 1951 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
8e50d384 1952 goto next_event;
514f1c67
ACM
1953 }
1954
fc551f8d 1955 if (sample.raw_data == NULL) {
c24ff998 1956 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
fc551f8d
ACM
1957 perf_evsel__name(evsel), sample.tid,
1958 sample.cpu, sample.raw_size);
8e50d384 1959 goto next_event;
fc551f8d
ACM
1960 }
1961
744a9719 1962 handler = evsel->handler;
ba3d7dee 1963 handler(trace, evsel, &sample);
8e50d384
ZZ
1964next_event:
1965 perf_evlist__mmap_consume(evlist, i);
20c5f10e 1966
ba209f85
ACM
1967 if (interrupted)
1968 goto out_disable;
514f1c67
ACM
1969 }
1970 }
1971
efd5745e 1972 if (trace->nr_events == before) {
ba209f85 1973 int timeout = done ? 100 : -1;
f15eb531 1974
ba209f85
ACM
1975 if (poll(evlist->pollfd, evlist->nr_fds, timeout) > 0)
1976 goto again;
1977 } else {
1978 goto again;
f15eb531
NK
1979 }
1980
ba209f85
ACM
1981out_disable:
1982 perf_evlist__disable(evlist);
514f1c67 1983
c522739d
ACM
1984 if (!err) {
1985 if (trace->summary)
1986 trace__fprintf_thread_summary(trace, trace->output);
1987
1988 if (trace->show_tool_stats) {
1989 fprintf(trace->output, "Stats:\n "
1990 " vfs_getname : %" PRIu64 "\n"
1991 " proc_getname: %" PRIu64 "\n",
1992 trace->stats.vfs_getname,
1993 trace->stats.proc_getname);
1994 }
1995 }
bf2575c1 1996
514f1c67
ACM
1997out_delete_evlist:
1998 perf_evlist__delete(evlist);
1999out:
75b757ca 2000 trace->live = false;
514f1c67 2001 return err;
6ef068cb
ACM
2002{
2003 char errbuf[BUFSIZ];
a8f23d8f
ACM
2004
2005out_error_tp:
6ef068cb 2006 perf_evlist__strerror_tp(evlist, errno, errbuf, sizeof(errbuf));
a8f23d8f
ACM
2007 goto out_error;
2008
2009out_error_open:
2010 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2011
2012out_error:
6ef068cb 2013 fprintf(trace->output, "%s\n", errbuf);
87f91868 2014 goto out_delete_evlist;
514f1c67 2015}
a8f23d8f 2016}
514f1c67 2017
6810fc91
DA
2018static int trace__replay(struct trace *trace)
2019{
2020 const struct perf_evsel_str_handler handlers[] = {
c522739d 2021 { "probe:vfs_getname", trace__vfs_getname, },
6810fc91 2022 };
f5fc1412
JO
2023 struct perf_data_file file = {
2024 .path = input_name,
2025 .mode = PERF_DATA_MODE_READ,
2026 };
6810fc91 2027 struct perf_session *session;
003824e8 2028 struct perf_evsel *evsel;
6810fc91
DA
2029 int err = -1;
2030
2031 trace->tool.sample = trace__process_sample;
2032 trace->tool.mmap = perf_event__process_mmap;
384c671e 2033 trace->tool.mmap2 = perf_event__process_mmap2;
6810fc91
DA
2034 trace->tool.comm = perf_event__process_comm;
2035 trace->tool.exit = perf_event__process_exit;
2036 trace->tool.fork = perf_event__process_fork;
2037 trace->tool.attr = perf_event__process_attr;
2038 trace->tool.tracing_data = perf_event__process_tracing_data;
2039 trace->tool.build_id = perf_event__process_build_id;
2040
2041 trace->tool.ordered_samples = true;
2042 trace->tool.ordering_requires_timestamps = true;
2043
2044 /* add tid to output */
2045 trace->multiple_threads = true;
2046
2047 if (symbol__init() < 0)
2048 return -1;
2049
f5fc1412 2050 session = perf_session__new(&file, false, &trace->tool);
6810fc91
DA
2051 if (session == NULL)
2052 return -ENOMEM;
2053
8fb598e5
DA
2054 trace->host = &session->machines.host;
2055
6810fc91
DA
2056 err = perf_session__set_tracepoints_handlers(session, handlers);
2057 if (err)
2058 goto out;
2059
003824e8
NK
2060 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2061 "raw_syscalls:sys_enter");
9aca7f17
DA
2062 /* older kernels have syscalls tp versus raw_syscalls */
2063 if (evsel == NULL)
2064 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2065 "syscalls:sys_enter");
003824e8
NK
2066 if (evsel == NULL) {
2067 pr_err("Data file does not have raw_syscalls:sys_enter event\n");
2068 goto out;
2069 }
2070
2071 if (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2072 perf_evsel__init_sc_tp_ptr_field(evsel, args)) {
2073 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2074 goto out;
2075 }
2076
2077 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2078 "raw_syscalls:sys_exit");
9aca7f17
DA
2079 if (evsel == NULL)
2080 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2081 "syscalls:sys_exit");
003824e8
NK
2082 if (evsel == NULL) {
2083 pr_err("Data file does not have raw_syscalls:sys_exit event\n");
6810fc91
DA
2084 goto out;
2085 }
2086
003824e8
NK
2087 if (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2088 perf_evsel__init_sc_tp_uint_field(evsel, ret)) {
2089 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
6810fc91
DA
2090 goto out;
2091 }
2092
bdc89661
DA
2093 err = parse_target_str(trace);
2094 if (err != 0)
2095 goto out;
2096
6810fc91
DA
2097 setup_pager();
2098
2099 err = perf_session__process_events(session, &trace->tool);
2100 if (err)
2101 pr_err("Failed to process events, error %d", err);
2102
bf2575c1
DA
2103 else if (trace->summary)
2104 trace__fprintf_thread_summary(trace, trace->output);
2105
6810fc91
DA
2106out:
2107 perf_session__delete(session);
2108
2109 return err;
2110}
2111
1302d88e
ACM
2112static size_t trace__fprintf_threads_header(FILE *fp)
2113{
2114 size_t printed;
2115
99ff7150 2116 printed = fprintf(fp, "\n Summary of events:\n\n");
bf2575c1
DA
2117
2118 return printed;
2119}
2120
2121static size_t thread__dump_stats(struct thread_trace *ttrace,
2122 struct trace *trace, FILE *fp)
2123{
2124 struct stats *stats;
2125 size_t printed = 0;
2126 struct syscall *sc;
2127 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2128
2129 if (inode == NULL)
2130 return 0;
2131
2132 printed += fprintf(fp, "\n");
2133
27a778b5
PE
2134 printed += fprintf(fp, " syscall calls min avg max stddev\n");
2135 printed += fprintf(fp, " (msec) (msec) (msec) (%%)\n");
2136 printed += fprintf(fp, " --------------- -------- --------- --------- --------- ------\n");
99ff7150 2137
bf2575c1
DA
2138 /* each int_node is a syscall */
2139 while (inode) {
2140 stats = inode->priv;
2141 if (stats) {
2142 double min = (double)(stats->min) / NSEC_PER_MSEC;
2143 double max = (double)(stats->max) / NSEC_PER_MSEC;
2144 double avg = avg_stats(stats);
2145 double pct;
2146 u64 n = (u64) stats->n;
2147
2148 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2149 avg /= NSEC_PER_MSEC;
2150
2151 sc = &trace->syscalls.table[inode->i];
99ff7150 2152 printed += fprintf(fp, " %-15s", sc->name);
27a778b5 2153 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f",
7f7a4138 2154 n, min, avg);
27a778b5 2155 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
bf2575c1
DA
2156 }
2157
2158 inode = intlist__next(inode);
2159 }
2160
2161 printed += fprintf(fp, "\n\n");
1302d88e
ACM
2162
2163 return printed;
2164}
2165
896cbb56
DA
2166/* struct used to pass data to per-thread function */
2167struct summary_data {
2168 FILE *fp;
2169 struct trace *trace;
2170 size_t printed;
2171};
2172
2173static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2174{
2175 struct summary_data *data = priv;
2176 FILE *fp = data->fp;
2177 size_t printed = data->printed;
2178 struct trace *trace = data->trace;
2179 struct thread_trace *ttrace = thread->priv;
896cbb56
DA
2180 double ratio;
2181
2182 if (ttrace == NULL)
2183 return 0;
2184
2185 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2186
15e65c69 2187 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
99ff7150 2188 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
15e65c69 2189 printed += fprintf(fp, "%.1f%%", ratio);
99ff7150 2190 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
bf2575c1 2191 printed += thread__dump_stats(ttrace, trace, fp);
896cbb56
DA
2192
2193 data->printed += printed;
2194
2195 return 0;
2196}
2197
1302d88e
ACM
2198static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2199{
896cbb56
DA
2200 struct summary_data data = {
2201 .fp = fp,
2202 .trace = trace
2203 };
2204 data.printed = trace__fprintf_threads_header(fp);
1302d88e 2205
896cbb56
DA
2206 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
2207
2208 return data.printed;
1302d88e
ACM
2209}
2210
ae9ed035
ACM
2211static int trace__set_duration(const struct option *opt, const char *str,
2212 int unset __maybe_unused)
2213{
2214 struct trace *trace = opt->value;
2215
2216 trace->duration_filter = atof(str);
2217 return 0;
2218}
2219
c24ff998
ACM
2220static int trace__open_output(struct trace *trace, const char *filename)
2221{
2222 struct stat st;
2223
2224 if (!stat(filename, &st) && st.st_size) {
2225 char oldname[PATH_MAX];
2226
2227 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2228 unlink(oldname);
2229 rename(filename, oldname);
2230 }
2231
2232 trace->output = fopen(filename, "w");
2233
2234 return trace->output == NULL ? -errno : 0;
2235}
2236
514f1c67
ACM
2237int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2238{
2239 const char * const trace_usage[] = {
f15eb531
NK
2240 "perf trace [<options>] [<command>]",
2241 "perf trace [<options>] -- <command> [<options>]",
5e2485b1
DA
2242 "perf trace record [<options>] [<command>]",
2243 "perf trace record [<options>] -- <command> [<options>]",
514f1c67
ACM
2244 NULL
2245 };
2246 struct trace trace = {
c522739d
ACM
2247 .audit = {
2248 .machine = audit_detect_machine(),
2249 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2250 },
514f1c67
ACM
2251 .syscalls = {
2252 . max = -1,
2253 },
2254 .opts = {
2255 .target = {
2256 .uid = UINT_MAX,
2257 .uses_mmap = true,
2258 },
2259 .user_freq = UINT_MAX,
2260 .user_interval = ULLONG_MAX,
509051ea 2261 .no_buffering = true,
514f1c67
ACM
2262 .mmap_pages = 1024,
2263 },
c24ff998 2264 .output = stdout,
50c95cbd 2265 .show_comm = true,
514f1c67 2266 };
c24ff998 2267 const char *output_name = NULL;
2ae3a312 2268 const char *ev_qualifier_str = NULL;
514f1c67 2269 const struct option trace_options[] = {
50c95cbd
ACM
2270 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2271 "show the thread COMM next to its id"),
c522739d 2272 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
2ae3a312
ACM
2273 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
2274 "list of events to trace"),
c24ff998 2275 OPT_STRING('o', "output", &output_name, "file", "output file name"),
6810fc91 2276 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
514f1c67
ACM
2277 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2278 "trace events on existing process id"),
ac9be8ee 2279 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
514f1c67 2280 "trace events on existing thread id"),
ac9be8ee 2281 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
514f1c67 2282 "system-wide collection from all CPUs"),
ac9be8ee 2283 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
514f1c67 2284 "list of cpus to monitor"),
6810fc91 2285 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
514f1c67 2286 "child tasks do not inherit counters"),
994a1f78
JO
2287 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2288 "number of mmap data pages",
2289 perf_evlist__parse_mmap_pages),
ac9be8ee 2290 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
514f1c67 2291 "user to profile"),
ae9ed035
ACM
2292 OPT_CALLBACK(0, "duration", &trace, "float",
2293 "show only events with duration > N.M ms",
2294 trace__set_duration),
1302d88e 2295 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
7c304ee0 2296 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
4bb09192
DA
2297 OPT_BOOLEAN('T', "time", &trace.full_time,
2298 "Show full timestamp, not time relative to first start"),
fd2eabaf
DA
2299 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2300 "Show only syscall summary with statistics"),
2301 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2302 "Show all syscalls and summary with statistics"),
514f1c67
ACM
2303 OPT_END()
2304 };
2305 int err;
32caf0d1 2306 char bf[BUFSIZ];
514f1c67 2307
5e2485b1
DA
2308 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
2309 return trace__record(argc-2, &argv[2]);
2310
514f1c67 2311 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
514f1c67 2312
fd2eabaf
DA
2313 /* summary_only implies summary option, but don't overwrite summary if set */
2314 if (trace.summary_only)
2315 trace.summary = trace.summary_only;
2316
c24ff998
ACM
2317 if (output_name != NULL) {
2318 err = trace__open_output(&trace, output_name);
2319 if (err < 0) {
2320 perror("failed to create output file");
2321 goto out;
2322 }
2323 }
2324
2ae3a312 2325 if (ev_qualifier_str != NULL) {
b059efdf
ACM
2326 const char *s = ev_qualifier_str;
2327
2328 trace.not_ev_qualifier = *s == '!';
2329 if (trace.not_ev_qualifier)
2330 ++s;
2331 trace.ev_qualifier = strlist__new(true, s);
2ae3a312 2332 if (trace.ev_qualifier == NULL) {
c24ff998
ACM
2333 fputs("Not enough memory to parse event qualifier",
2334 trace.output);
2335 err = -ENOMEM;
2336 goto out_close;
2ae3a312
ACM
2337 }
2338 }
2339
602ad878 2340 err = target__validate(&trace.opts.target);
32caf0d1 2341 if (err) {
602ad878 2342 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
2343 fprintf(trace.output, "%s", bf);
2344 goto out_close;
32caf0d1
NK
2345 }
2346
602ad878 2347 err = target__parse_uid(&trace.opts.target);
514f1c67 2348 if (err) {
602ad878 2349 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
2350 fprintf(trace.output, "%s", bf);
2351 goto out_close;
514f1c67
ACM
2352 }
2353
602ad878 2354 if (!argc && target__none(&trace.opts.target))
ee76120e
NK
2355 trace.opts.target.system_wide = true;
2356
6810fc91
DA
2357 if (input_name)
2358 err = trace__replay(&trace);
2359 else
2360 err = trace__run(&trace, argc, argv);
1302d88e 2361
c24ff998
ACM
2362out_close:
2363 if (output_name != NULL)
2364 fclose(trace.output);
2365out:
1302d88e 2366 return err;
514f1c67 2367}