perf trace: Beautify eventfd2 'flags' arg
[deliverable/linux.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"
514f1c67
ACM
13
14#include <libaudit.h>
15#include <stdlib.h>
49af9e93 16#include <sys/eventfd.h>
ae685380 17#include <sys/mman.h>
f9da0b0c 18#include <linux/futex.h>
514f1c67 19
456857bd
IM
20/* For older distros: */
21#ifndef MAP_STACK
22# define MAP_STACK 0x20000
23#endif
24
25#ifndef MADV_HWPOISON
26# define MADV_HWPOISON 100
27#endif
28
29#ifndef MADV_MERGEABLE
30# define MADV_MERGEABLE 12
31#endif
32
33#ifndef MADV_UNMERGEABLE
34# define MADV_UNMERGEABLE 13
35#endif
36
01533e97
ACM
37struct syscall_arg {
38 unsigned long val;
1f115cb7 39 void *parm;
01533e97
ACM
40 u8 idx;
41 u8 mask;
42};
43
1f115cb7
ACM
44struct strarray {
45 int nr_entries;
46 const char **entries;
47};
48
49#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
50 .nr_entries = ARRAY_SIZE(array), \
51 .entries = array, \
52}
53
54static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
55 struct syscall_arg *arg)
56{
57 int idx = arg->val;
58 struct strarray *sa = arg->parm;
59
60 if (idx < 0 || idx >= sa->nr_entries)
61 return scnprintf(bf, size, "%d", idx);
62
63 return scnprintf(bf, size, "%s", sa->entries[idx]);
64}
65
66#define SCA_STRARRAY syscall_arg__scnprintf_strarray
67
6e7eeb51 68static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
01533e97 69 struct syscall_arg *arg)
13d4ff3e 70{
01533e97 71 return scnprintf(bf, size, "%#lx", arg->val);
13d4ff3e
ACM
72}
73
beccb2b5
ACM
74#define SCA_HEX syscall_arg__scnprintf_hex
75
6e7eeb51 76static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
01533e97 77 struct syscall_arg *arg)
ae685380 78{
01533e97 79 int printed = 0, prot = arg->val;
ae685380
ACM
80
81 if (prot == PROT_NONE)
82 return scnprintf(bf, size, "NONE");
83#define P_MMAP_PROT(n) \
84 if (prot & PROT_##n) { \
85 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
86 prot &= ~PROT_##n; \
87 }
88
89 P_MMAP_PROT(EXEC);
90 P_MMAP_PROT(READ);
91 P_MMAP_PROT(WRITE);
92#ifdef PROT_SEM
93 P_MMAP_PROT(SEM);
94#endif
95 P_MMAP_PROT(GROWSDOWN);
96 P_MMAP_PROT(GROWSUP);
97#undef P_MMAP_PROT
98
99 if (prot)
100 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
101
102 return printed;
103}
104
105#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
106
6e7eeb51 107static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
01533e97 108 struct syscall_arg *arg)
941557e0 109{
01533e97 110 int printed = 0, flags = arg->val;
941557e0
ACM
111
112#define P_MMAP_FLAG(n) \
113 if (flags & MAP_##n) { \
114 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
115 flags &= ~MAP_##n; \
116 }
117
118 P_MMAP_FLAG(SHARED);
119 P_MMAP_FLAG(PRIVATE);
41817815 120#ifdef MAP_32BIT
941557e0 121 P_MMAP_FLAG(32BIT);
41817815 122#endif
941557e0
ACM
123 P_MMAP_FLAG(ANONYMOUS);
124 P_MMAP_FLAG(DENYWRITE);
125 P_MMAP_FLAG(EXECUTABLE);
126 P_MMAP_FLAG(FILE);
127 P_MMAP_FLAG(FIXED);
128 P_MMAP_FLAG(GROWSDOWN);
f2935f3e 129#ifdef MAP_HUGETLB
941557e0 130 P_MMAP_FLAG(HUGETLB);
f2935f3e 131#endif
941557e0
ACM
132 P_MMAP_FLAG(LOCKED);
133 P_MMAP_FLAG(NONBLOCK);
134 P_MMAP_FLAG(NORESERVE);
135 P_MMAP_FLAG(POPULATE);
136 P_MMAP_FLAG(STACK);
137#ifdef MAP_UNINITIALIZED
138 P_MMAP_FLAG(UNINITIALIZED);
139#endif
140#undef P_MMAP_FLAG
141
142 if (flags)
143 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
144
145 return printed;
146}
147
148#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
149
6e7eeb51 150static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
01533e97 151 struct syscall_arg *arg)
9e9716d1 152{
01533e97 153 int behavior = arg->val;
9e9716d1
ACM
154
155 switch (behavior) {
156#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
157 P_MADV_BHV(NORMAL);
158 P_MADV_BHV(RANDOM);
159 P_MADV_BHV(SEQUENTIAL);
160 P_MADV_BHV(WILLNEED);
161 P_MADV_BHV(DONTNEED);
162 P_MADV_BHV(REMOVE);
163 P_MADV_BHV(DONTFORK);
164 P_MADV_BHV(DOFORK);
165 P_MADV_BHV(HWPOISON);
166#ifdef MADV_SOFT_OFFLINE
167 P_MADV_BHV(SOFT_OFFLINE);
168#endif
169 P_MADV_BHV(MERGEABLE);
170 P_MADV_BHV(UNMERGEABLE);
f2935f3e 171#ifdef MADV_HUGEPAGE
9e9716d1 172 P_MADV_BHV(HUGEPAGE);
f2935f3e
DA
173#endif
174#ifdef MADV_NOHUGEPAGE
9e9716d1 175 P_MADV_BHV(NOHUGEPAGE);
f2935f3e 176#endif
9e9716d1
ACM
177#ifdef MADV_DONTDUMP
178 P_MADV_BHV(DONTDUMP);
179#endif
180#ifdef MADV_DODUMP
181 P_MADV_BHV(DODUMP);
182#endif
183#undef P_MADV_PHV
184 default: break;
185 }
186
187 return scnprintf(bf, size, "%#x", behavior);
188}
189
190#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
191
01533e97 192static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
f9da0b0c
ACM
193{
194 enum syscall_futex_args {
195 SCF_UADDR = (1 << 0),
196 SCF_OP = (1 << 1),
197 SCF_VAL = (1 << 2),
198 SCF_TIMEOUT = (1 << 3),
199 SCF_UADDR2 = (1 << 4),
200 SCF_VAL3 = (1 << 5),
201 };
01533e97 202 int op = arg->val;
f9da0b0c
ACM
203 int cmd = op & FUTEX_CMD_MASK;
204 size_t printed = 0;
205
206 switch (cmd) {
207#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
01533e97
ACM
208 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
209 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
210 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
211 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
212 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
213 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
f9da0b0c 214 P_FUTEX_OP(WAKE_OP); break;
01533e97
ACM
215 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
216 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
217 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
218 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
219 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
f9da0b0c
ACM
220 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
221 default: printed = scnprintf(bf, size, "%#x", cmd); break;
222 }
223
224 if (op & FUTEX_PRIVATE_FLAG)
225 printed += scnprintf(bf + printed, size - printed, "|PRIV");
226
227 if (op & FUTEX_CLOCK_REALTIME)
228 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
229
230 return printed;
231}
232
efe6b882
ACM
233#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
234
1f115cb7
ACM
235static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
236static DEFINE_STRARRAY(itimers);
237
efe6b882
ACM
238static const char *whences[] = { "SET", "CUR", "END",
239#ifdef SEEK_DATA
240"DATA",
241#endif
242#ifdef SEEK_HOLE
243"HOLE",
244#endif
245};
246static DEFINE_STRARRAY(whences);
f9da0b0c 247
80f587d5
ACM
248static const char *fcntl_cmds[] = {
249 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
250 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
251 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
252 "F_GETOWNER_UIDS",
253};
254static DEFINE_STRARRAY(fcntl_cmds);
255
c045bf02
ACM
256static const char *rlimit_resources[] = {
257 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
258 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
259 "RTTIME",
260};
261static DEFINE_STRARRAY(rlimit_resources);
262
eb5b1b14
ACM
263static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
264static DEFINE_STRARRAY(sighow);
265
e10bce81
ACM
266static const char *socket_families[] = {
267 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
268 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
269 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
270 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
271 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
272 "ALG", "NFC", "VSOCK",
273};
274static DEFINE_STRARRAY(socket_families);
275
a28b24b2
ACM
276#ifndef SOCK_TYPE_MASK
277#define SOCK_TYPE_MASK 0xf
278#endif
279
280static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
281 struct syscall_arg *arg)
282{
283 size_t printed;
284 int type = arg->val,
285 flags = type & ~SOCK_TYPE_MASK;
286
287 type &= SOCK_TYPE_MASK;
288 /*
289 * Can't use a strarray, MIPS may override for ABI reasons.
290 */
291 switch (type) {
292#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
293 P_SK_TYPE(STREAM);
294 P_SK_TYPE(DGRAM);
295 P_SK_TYPE(RAW);
296 P_SK_TYPE(RDM);
297 P_SK_TYPE(SEQPACKET);
298 P_SK_TYPE(DCCP);
299 P_SK_TYPE(PACKET);
300#undef P_SK_TYPE
301 default:
302 printed = scnprintf(bf, size, "%#x", type);
303 }
304
305#define P_SK_FLAG(n) \
306 if (flags & SOCK_##n) { \
307 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
308 flags &= ~SOCK_##n; \
309 }
310
311 P_SK_FLAG(CLOEXEC);
312 P_SK_FLAG(NONBLOCK);
313#undef P_SK_FLAG
314
315 if (flags)
316 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
317
318 return printed;
319}
320
321#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
322
b2cc99fd
ACM
323#ifndef MSG_PROBE
324#define MSG_PROBE 0x10
325#endif
326#ifndef MSG_SENDPAGE_NOTLAST
327#define MSG_SENDPAGE_NOTLAST 0x20000
328#endif
329#ifndef MSG_FASTOPEN
330#define MSG_FASTOPEN 0x20000000
331#endif
332
333static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
334 struct syscall_arg *arg)
335{
336 int printed = 0, flags = arg->val;
337
338 if (flags == 0)
339 return scnprintf(bf, size, "NONE");
340#define P_MSG_FLAG(n) \
341 if (flags & MSG_##n) { \
342 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
343 flags &= ~MSG_##n; \
344 }
345
346 P_MSG_FLAG(OOB);
347 P_MSG_FLAG(PEEK);
348 P_MSG_FLAG(DONTROUTE);
349 P_MSG_FLAG(TRYHARD);
350 P_MSG_FLAG(CTRUNC);
351 P_MSG_FLAG(PROBE);
352 P_MSG_FLAG(TRUNC);
353 P_MSG_FLAG(DONTWAIT);
354 P_MSG_FLAG(EOR);
355 P_MSG_FLAG(WAITALL);
356 P_MSG_FLAG(FIN);
357 P_MSG_FLAG(SYN);
358 P_MSG_FLAG(CONFIRM);
359 P_MSG_FLAG(RST);
360 P_MSG_FLAG(ERRQUEUE);
361 P_MSG_FLAG(NOSIGNAL);
362 P_MSG_FLAG(MORE);
363 P_MSG_FLAG(WAITFORONE);
364 P_MSG_FLAG(SENDPAGE_NOTLAST);
365 P_MSG_FLAG(FASTOPEN);
366 P_MSG_FLAG(CMSG_CLOEXEC);
367#undef P_MSG_FLAG
368
369 if (flags)
370 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
371
372 return printed;
373}
374
375#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
376
51108999
ACM
377static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
378 struct syscall_arg *arg)
379{
380 size_t printed = 0;
381 int mode = arg->val;
382
383 if (mode == F_OK) /* 0 */
384 return scnprintf(bf, size, "F");
385#define P_MODE(n) \
386 if (mode & n##_OK) { \
387 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
388 mode &= ~n##_OK; \
389 }
390
391 P_MODE(R);
392 P_MODE(W);
393 P_MODE(X);
394#undef P_MODE
395
396 if (mode)
397 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
398
399 return printed;
400}
401
402#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
403
be65a89a 404static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
01533e97 405 struct syscall_arg *arg)
be65a89a 406{
01533e97 407 int printed = 0, flags = arg->val;
be65a89a
ACM
408
409 if (!(flags & O_CREAT))
01533e97 410 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
be65a89a
ACM
411
412 if (flags == 0)
413 return scnprintf(bf, size, "RDONLY");
414#define P_FLAG(n) \
415 if (flags & O_##n) { \
416 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
417 flags &= ~O_##n; \
418 }
419
420 P_FLAG(APPEND);
421 P_FLAG(ASYNC);
422 P_FLAG(CLOEXEC);
423 P_FLAG(CREAT);
424 P_FLAG(DIRECT);
425 P_FLAG(DIRECTORY);
426 P_FLAG(EXCL);
427 P_FLAG(LARGEFILE);
428 P_FLAG(NOATIME);
429 P_FLAG(NOCTTY);
430#ifdef O_NONBLOCK
431 P_FLAG(NONBLOCK);
432#elif O_NDELAY
433 P_FLAG(NDELAY);
434#endif
435#ifdef O_PATH
436 P_FLAG(PATH);
437#endif
438 P_FLAG(RDWR);
439#ifdef O_DSYNC
440 if ((flags & O_SYNC) == O_SYNC)
441 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
442 else {
443 P_FLAG(DSYNC);
444 }
445#else
446 P_FLAG(SYNC);
447#endif
448 P_FLAG(TRUNC);
449 P_FLAG(WRONLY);
450#undef P_FLAG
451
452 if (flags)
453 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
454
455 return printed;
456}
457
458#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
459
49af9e93
ACM
460static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
461 struct syscall_arg *arg)
462{
463 int printed = 0, flags = arg->val;
464
465 if (flags == 0)
466 return scnprintf(bf, size, "NONE");
467#define P_FLAG(n) \
468 if (flags & EFD_##n) { \
469 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
470 flags &= ~EFD_##n; \
471 }
472
473 P_FLAG(SEMAPHORE);
474 P_FLAG(CLOEXEC);
475 P_FLAG(NONBLOCK);
476#undef P_FLAG
477
478 if (flags)
479 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
480
481 return printed;
482}
483
484#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
485
8bad5b0a
ACM
486static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
487{
488 int sig = arg->val;
489
490 switch (sig) {
491#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
492 P_SIGNUM(HUP);
493 P_SIGNUM(INT);
494 P_SIGNUM(QUIT);
495 P_SIGNUM(ILL);
496 P_SIGNUM(TRAP);
497 P_SIGNUM(ABRT);
498 P_SIGNUM(BUS);
499 P_SIGNUM(FPE);
500 P_SIGNUM(KILL);
501 P_SIGNUM(USR1);
502 P_SIGNUM(SEGV);
503 P_SIGNUM(USR2);
504 P_SIGNUM(PIPE);
505 P_SIGNUM(ALRM);
506 P_SIGNUM(TERM);
507 P_SIGNUM(STKFLT);
508 P_SIGNUM(CHLD);
509 P_SIGNUM(CONT);
510 P_SIGNUM(STOP);
511 P_SIGNUM(TSTP);
512 P_SIGNUM(TTIN);
513 P_SIGNUM(TTOU);
514 P_SIGNUM(URG);
515 P_SIGNUM(XCPU);
516 P_SIGNUM(XFSZ);
517 P_SIGNUM(VTALRM);
518 P_SIGNUM(PROF);
519 P_SIGNUM(WINCH);
520 P_SIGNUM(IO);
521 P_SIGNUM(PWR);
522 P_SIGNUM(SYS);
523 default: break;
524 }
525
526 return scnprintf(bf, size, "%#x", sig);
527}
528
529#define SCA_SIGNUM syscall_arg__scnprintf_signum
530
514f1c67
ACM
531static struct syscall_fmt {
532 const char *name;
aec1930b 533 const char *alias;
01533e97 534 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
1f115cb7 535 void *arg_parm[6];
514f1c67
ACM
536 bool errmsg;
537 bool timeout;
04b34729 538 bool hexret;
514f1c67 539} syscall_fmts[] = {
51108999
ACM
540 { .name = "access", .errmsg = true,
541 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
aec1930b 542 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
beccb2b5
ACM
543 { .name = "brk", .hexret = true,
544 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
a14bb860 545 { .name = "connect", .errmsg = true, },
49af9e93
ACM
546 { .name = "eventfd2", .errmsg = true,
547 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
80f587d5
ACM
548 { .name = "fcntl", .errmsg = true,
549 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
550 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
aec1930b
ACM
551 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
552 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
f9da0b0c
ACM
553 { .name = "futex", .errmsg = true,
554 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
1f115cb7
ACM
555 { .name = "getitimer", .errmsg = true,
556 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
557 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
c045bf02
ACM
558 { .name = "getrlimit", .errmsg = true,
559 .arg_scnprintf = { [0] = SCA_STRARRAY, /* resource */ },
560 .arg_parm = { [0] = &strarray__rlimit_resources, /* resource */ }, },
beccb2b5
ACM
561 { .name = "ioctl", .errmsg = true,
562 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
8bad5b0a
ACM
563 { .name = "kill", .errmsg = true,
564 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
579e7865 565 { .name = "lseek", .errmsg = true,
efe6b882
ACM
566 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
567 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
e5959683 568 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
9e9716d1
ACM
569 { .name = "madvise", .errmsg = true,
570 .arg_scnprintf = { [0] = SCA_HEX, /* start */
571 [2] = SCA_MADV_BHV, /* behavior */ }, },
beccb2b5 572 { .name = "mmap", .hexret = true,
ae685380 573 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
941557e0
ACM
574 [2] = SCA_MMAP_PROT, /* prot */
575 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
beccb2b5 576 { .name = "mprotect", .errmsg = true,
ae685380
ACM
577 .arg_scnprintf = { [0] = SCA_HEX, /* start */
578 [2] = SCA_MMAP_PROT, /* prot */ }, },
579 { .name = "mremap", .hexret = true,
580 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
581 [4] = SCA_HEX, /* new_addr */ }, },
beccb2b5
ACM
582 { .name = "munmap", .errmsg = true,
583 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
be65a89a
ACM
584 { .name = "open", .errmsg = true,
585 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
31cd3855
ACM
586 { .name = "open_by_handle_at", .errmsg = true,
587 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
588 { .name = "openat", .errmsg = true,
589 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
aec1930b
ACM
590 { .name = "poll", .errmsg = true, .timeout = true, },
591 { .name = "ppoll", .errmsg = true, .timeout = true, },
e5959683 592 { .name = "pread", .errmsg = true, .alias = "pread64", },
c045bf02
ACM
593 { .name = "prlimit64", .errmsg = true,
594 .arg_scnprintf = { [1] = SCA_STRARRAY, /* resource */ },
595 .arg_parm = { [1] = &strarray__rlimit_resources, /* resource */ }, },
e5959683 596 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
aec1930b 597 { .name = "read", .errmsg = true, },
b2cc99fd
ACM
598 { .name = "recvfrom", .errmsg = true,
599 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
600 { .name = "recvmmsg", .errmsg = true,
601 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
602 { .name = "recvmsg", .errmsg = true,
603 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
8bad5b0a
ACM
604 { .name = "rt_sigaction", .errmsg = true,
605 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
eb5b1b14
ACM
606 { .name = "rt_sigprocmask", .errmsg = true,
607 .arg_scnprintf = { [0] = SCA_STRARRAY, /* how */ },
608 .arg_parm = { [0] = &strarray__sighow, /* how */ }, },
8bad5b0a
ACM
609 { .name = "rt_sigqueueinfo", .errmsg = true,
610 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
611 { .name = "rt_tgsigqueueinfo", .errmsg = true,
612 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
aec1930b 613 { .name = "select", .errmsg = true, .timeout = true, },
b2cc99fd
ACM
614 { .name = "sendmmsg", .errmsg = true,
615 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
616 { .name = "sendmsg", .errmsg = true,
617 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
618 { .name = "sendto", .errmsg = true,
619 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1f115cb7
ACM
620 { .name = "setitimer", .errmsg = true,
621 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
622 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
c045bf02
ACM
623 { .name = "setrlimit", .errmsg = true,
624 .arg_scnprintf = { [0] = SCA_STRARRAY, /* resource */ },
625 .arg_parm = { [0] = &strarray__rlimit_resources, /* resource */ }, },
e10bce81 626 { .name = "socket", .errmsg = true,
a28b24b2
ACM
627 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
628 [1] = SCA_SK_TYPE, /* type */ },
e10bce81 629 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
aec1930b 630 { .name = "stat", .errmsg = true, .alias = "newstat", },
8bad5b0a
ACM
631 { .name = "tgkill", .errmsg = true,
632 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
633 { .name = "tkill", .errmsg = true,
634 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
e5959683 635 { .name = "uname", .errmsg = true, .alias = "newuname", },
514f1c67
ACM
636};
637
638static int syscall_fmt__cmp(const void *name, const void *fmtp)
639{
640 const struct syscall_fmt *fmt = fmtp;
641 return strcmp(name, fmt->name);
642}
643
644static struct syscall_fmt *syscall_fmt__find(const char *name)
645{
646 const int nmemb = ARRAY_SIZE(syscall_fmts);
647 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
648}
649
650struct syscall {
651 struct event_format *tp_format;
652 const char *name;
2ae3a312 653 bool filtered;
514f1c67 654 struct syscall_fmt *fmt;
01533e97 655 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
1f115cb7 656 void **arg_parm;
514f1c67
ACM
657};
658
60c907ab
ACM
659static size_t fprintf_duration(unsigned long t, FILE *fp)
660{
661 double duration = (double)t / NSEC_PER_MSEC;
662 size_t printed = fprintf(fp, "(");
663
664 if (duration >= 1.0)
665 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
666 else if (duration >= 0.01)
667 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
668 else
669 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
c24ff998 670 return printed + fprintf(fp, "): ");
60c907ab
ACM
671}
672
752fde44
ACM
673struct thread_trace {
674 u64 entry_time;
675 u64 exit_time;
676 bool entry_pending;
efd5745e 677 unsigned long nr_events;
752fde44 678 char *entry_str;
1302d88e 679 double runtime_ms;
752fde44
ACM
680};
681
682static struct thread_trace *thread_trace__new(void)
683{
684 return zalloc(sizeof(struct thread_trace));
685}
686
c24ff998 687static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
752fde44 688{
efd5745e
ACM
689 struct thread_trace *ttrace;
690
752fde44
ACM
691 if (thread == NULL)
692 goto fail;
693
694 if (thread->priv == NULL)
695 thread->priv = thread_trace__new();
efd5745e 696
752fde44
ACM
697 if (thread->priv == NULL)
698 goto fail;
699
efd5745e
ACM
700 ttrace = thread->priv;
701 ++ttrace->nr_events;
702
703 return ttrace;
752fde44 704fail:
c24ff998 705 color_fprintf(fp, PERF_COLOR_RED,
752fde44
ACM
706 "WARNING: not enough memory, dropping samples!\n");
707 return NULL;
708}
709
514f1c67 710struct trace {
c24ff998 711 struct perf_tool tool;
514f1c67
ACM
712 int audit_machine;
713 struct {
714 int max;
715 struct syscall *table;
716 } syscalls;
717 struct perf_record_opts opts;
752fde44
ACM
718 struct machine host;
719 u64 base_time;
4bb09192 720 bool full_time;
c24ff998 721 FILE *output;
efd5745e 722 unsigned long nr_events;
b059efdf
ACM
723 struct strlist *ev_qualifier;
724 bool not_ev_qualifier;
bdc89661
DA
725 struct intlist *tid_list;
726 struct intlist *pid_list;
1302d88e 727 bool sched;
752fde44 728 bool multiple_threads;
ae9ed035 729 double duration_filter;
1302d88e 730 double runtime_ms;
514f1c67
ACM
731};
732
ae9ed035
ACM
733static bool trace__filter_duration(struct trace *trace, double t)
734{
735 return t < (trace->duration_filter * NSEC_PER_MSEC);
736}
737
752fde44
ACM
738static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
739{
740 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
741
60c907ab 742 return fprintf(fp, "%10.3f ", ts);
752fde44
ACM
743}
744
f15eb531
NK
745static bool done = false;
746
747static void sig_handler(int sig __maybe_unused)
748{
749 done = true;
750}
751
752fde44 752static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
60c907ab 753 u64 duration, u64 tstamp, FILE *fp)
752fde44
ACM
754{
755 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
60c907ab 756 printed += fprintf_duration(duration, fp);
752fde44
ACM
757
758 if (trace->multiple_threads)
38051234 759 printed += fprintf(fp, "%d ", thread->tid);
752fde44
ACM
760
761 return printed;
762}
763
c24ff998
ACM
764static int trace__process_event(struct trace *trace, struct machine *machine,
765 union perf_event *event)
752fde44
ACM
766{
767 int ret = 0;
768
769 switch (event->header.type) {
770 case PERF_RECORD_LOST:
c24ff998 771 color_fprintf(trace->output, PERF_COLOR_RED,
752fde44
ACM
772 "LOST %" PRIu64 " events!\n", event->lost.lost);
773 ret = machine__process_lost_event(machine, event);
774 default:
775 ret = machine__process_event(machine, event);
776 break;
777 }
778
779 return ret;
780}
781
c24ff998 782static int trace__tool_process(struct perf_tool *tool,
752fde44
ACM
783 union perf_event *event,
784 struct perf_sample *sample __maybe_unused,
785 struct machine *machine)
786{
c24ff998
ACM
787 struct trace *trace = container_of(tool, struct trace, tool);
788 return trace__process_event(trace, machine, event);
752fde44
ACM
789}
790
791static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
792{
793 int err = symbol__init();
794
795 if (err)
796 return err;
797
798 machine__init(&trace->host, "", HOST_KERNEL_ID);
799 machine__create_kernel_maps(&trace->host);
800
801 if (perf_target__has_task(&trace->opts.target)) {
c24ff998 802 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
752fde44
ACM
803 trace__tool_process,
804 &trace->host);
805 } else {
c24ff998 806 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
752fde44
ACM
807 &trace->host);
808 }
809
810 if (err)
811 symbol__exit();
812
813 return err;
814}
815
13d4ff3e
ACM
816static int syscall__set_arg_fmts(struct syscall *sc)
817{
818 struct format_field *field;
819 int idx = 0;
820
821 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
822 if (sc->arg_scnprintf == NULL)
823 return -1;
824
1f115cb7
ACM
825 if (sc->fmt)
826 sc->arg_parm = sc->fmt->arg_parm;
827
13d4ff3e 828 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
beccb2b5
ACM
829 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
830 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
831 else if (field->flags & FIELD_IS_POINTER)
13d4ff3e
ACM
832 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
833 ++idx;
834 }
835
836 return 0;
837}
838
514f1c67
ACM
839static int trace__read_syscall_info(struct trace *trace, int id)
840{
841 char tp_name[128];
842 struct syscall *sc;
3a531260
ACM
843 const char *name = audit_syscall_to_name(id, trace->audit_machine);
844
845 if (name == NULL)
846 return -1;
514f1c67
ACM
847
848 if (id > trace->syscalls.max) {
849 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
850
851 if (nsyscalls == NULL)
852 return -1;
853
854 if (trace->syscalls.max != -1) {
855 memset(nsyscalls + trace->syscalls.max + 1, 0,
856 (id - trace->syscalls.max) * sizeof(*sc));
857 } else {
858 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
859 }
860
861 trace->syscalls.table = nsyscalls;
862 trace->syscalls.max = id;
863 }
864
865 sc = trace->syscalls.table + id;
3a531260 866 sc->name = name;
2ae3a312 867
b059efdf
ACM
868 if (trace->ev_qualifier) {
869 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
870
871 if (!(in ^ trace->not_ev_qualifier)) {
872 sc->filtered = true;
873 /*
874 * No need to do read tracepoint information since this will be
875 * filtered out.
876 */
877 return 0;
878 }
2ae3a312
ACM
879 }
880
3a531260 881 sc->fmt = syscall_fmt__find(sc->name);
514f1c67 882
aec1930b 883 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
514f1c67 884 sc->tp_format = event_format__new("syscalls", tp_name);
aec1930b
ACM
885
886 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
887 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
888 sc->tp_format = event_format__new("syscalls", tp_name);
889 }
514f1c67 890
13d4ff3e
ACM
891 if (sc->tp_format == NULL)
892 return -1;
893
894 return syscall__set_arg_fmts(sc);
514f1c67
ACM
895}
896
752fde44
ACM
897static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
898 unsigned long *args)
514f1c67 899{
514f1c67
ACM
900 size_t printed = 0;
901
902 if (sc->tp_format != NULL) {
903 struct format_field *field;
01533e97
ACM
904 u8 bit = 1;
905 struct syscall_arg arg = {
906 .idx = 0,
907 .mask = 0,
908 };
6e7eeb51
ACM
909
910 for (field = sc->tp_format->format.fields->next; field;
01533e97
ACM
911 field = field->next, ++arg.idx, bit <<= 1) {
912 if (arg.mask & bit)
6e7eeb51 913 continue;
514f1c67 914
22ae5cf1
ACM
915 if (args[arg.idx] == 0)
916 continue;
917
752fde44 918 printed += scnprintf(bf + printed, size - printed,
13d4ff3e 919 "%s%s: ", printed ? ", " : "", field->name);
01533e97
ACM
920 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
921 arg.val = args[arg.idx];
1f115cb7
ACM
922 if (sc->arg_parm)
923 arg.parm = sc->arg_parm[arg.idx];
01533e97
ACM
924 printed += sc->arg_scnprintf[arg.idx](bf + printed,
925 size - printed, &arg);
6e7eeb51 926 } else {
13d4ff3e 927 printed += scnprintf(bf + printed, size - printed,
01533e97 928 "%ld", args[arg.idx]);
6e7eeb51 929 }
514f1c67
ACM
930 }
931 } else {
01533e97
ACM
932 int i = 0;
933
514f1c67 934 while (i < 6) {
752fde44
ACM
935 printed += scnprintf(bf + printed, size - printed,
936 "%sarg%d: %ld",
937 printed ? ", " : "", i, args[i]);
514f1c67
ACM
938 ++i;
939 }
940 }
941
942 return printed;
943}
944
ba3d7dee
ACM
945typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
946 struct perf_sample *sample);
947
948static struct syscall *trace__syscall_info(struct trace *trace,
949 struct perf_evsel *evsel,
950 struct perf_sample *sample)
951{
952 int id = perf_evsel__intval(evsel, sample, "id");
953
954 if (id < 0) {
adaa18bf
ACM
955
956 /*
957 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
958 * before that, leaving at a higher verbosity level till that is
959 * explained. Reproduced with plain ftrace with:
960 *
961 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
962 * grep "NR -1 " /t/trace_pipe
963 *
964 * After generating some load on the machine.
965 */
966 if (verbose > 1) {
967 static u64 n;
968 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
969 id, perf_evsel__name(evsel), ++n);
970 }
ba3d7dee
ACM
971 return NULL;
972 }
973
974 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
975 trace__read_syscall_info(trace, id))
976 goto out_cant_read;
977
978 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
979 goto out_cant_read;
980
981 return &trace->syscalls.table[id];
982
983out_cant_read:
7c304ee0
ACM
984 if (verbose) {
985 fprintf(trace->output, "Problems reading syscall %d", id);
986 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
987 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
988 fputs(" information\n", trace->output);
989 }
ba3d7dee
ACM
990 return NULL;
991}
992
993static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
994 struct perf_sample *sample)
995{
752fde44 996 char *msg;
ba3d7dee 997 void *args;
752fde44 998 size_t printed = 0;
2ae3a312 999 struct thread *thread;
ba3d7dee 1000 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
2ae3a312
ACM
1001 struct thread_trace *ttrace;
1002
1003 if (sc == NULL)
1004 return -1;
ba3d7dee 1005
2ae3a312
ACM
1006 if (sc->filtered)
1007 return 0;
1008
314add6b
AH
1009 thread = machine__findnew_thread(&trace->host, sample->pid,
1010 sample->tid);
c24ff998 1011 ttrace = thread__trace(thread, trace->output);
2ae3a312 1012 if (ttrace == NULL)
ba3d7dee
ACM
1013 return -1;
1014
1015 args = perf_evsel__rawptr(evsel, sample, "args");
1016 if (args == NULL) {
c24ff998 1017 fprintf(trace->output, "Problems reading syscall arguments\n");
ba3d7dee
ACM
1018 return -1;
1019 }
1020
752fde44
ACM
1021 ttrace = thread->priv;
1022
1023 if (ttrace->entry_str == NULL) {
1024 ttrace->entry_str = malloc(1024);
1025 if (!ttrace->entry_str)
1026 return -1;
1027 }
1028
1029 ttrace->entry_time = sample->time;
1030 msg = ttrace->entry_str;
1031 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1032
1033 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
1034
1035 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
ae9ed035 1036 if (!trace->duration_filter) {
c24ff998
ACM
1037 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1038 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
ae9ed035 1039 }
752fde44
ACM
1040 } else
1041 ttrace->entry_pending = true;
ba3d7dee
ACM
1042
1043 return 0;
1044}
1045
1046static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1047 struct perf_sample *sample)
1048{
1049 int ret;
60c907ab 1050 u64 duration = 0;
2ae3a312 1051 struct thread *thread;
ba3d7dee 1052 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
2ae3a312
ACM
1053 struct thread_trace *ttrace;
1054
1055 if (sc == NULL)
1056 return -1;
ba3d7dee 1057
2ae3a312
ACM
1058 if (sc->filtered)
1059 return 0;
1060
314add6b
AH
1061 thread = machine__findnew_thread(&trace->host, sample->pid,
1062 sample->tid);
c24ff998 1063 ttrace = thread__trace(thread, trace->output);
2ae3a312 1064 if (ttrace == NULL)
ba3d7dee
ACM
1065 return -1;
1066
1067 ret = perf_evsel__intval(evsel, sample, "ret");
1068
752fde44
ACM
1069 ttrace = thread->priv;
1070
1071 ttrace->exit_time = sample->time;
1072
ae9ed035 1073 if (ttrace->entry_time) {
60c907ab 1074 duration = sample->time - ttrace->entry_time;
ae9ed035
ACM
1075 if (trace__filter_duration(trace, duration))
1076 goto out;
1077 } else if (trace->duration_filter)
1078 goto out;
60c907ab 1079
c24ff998 1080 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
752fde44
ACM
1081
1082 if (ttrace->entry_pending) {
c24ff998 1083 fprintf(trace->output, "%-70s", ttrace->entry_str);
752fde44 1084 } else {
c24ff998
ACM
1085 fprintf(trace->output, " ... [");
1086 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1087 fprintf(trace->output, "]: %s()", sc->name);
752fde44
ACM
1088 }
1089
da3c9a44
ACM
1090 if (sc->fmt == NULL) {
1091signed_print:
1092 fprintf(trace->output, ") = %d", ret);
1093 } else if (ret < 0 && sc->fmt->errmsg) {
ba3d7dee
ACM
1094 char bf[256];
1095 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1096 *e = audit_errno_to_name(-ret);
1097
c24ff998 1098 fprintf(trace->output, ") = -1 %s %s", e, emsg);
da3c9a44 1099 } else if (ret == 0 && sc->fmt->timeout)
c24ff998 1100 fprintf(trace->output, ") = 0 Timeout");
04b34729
ACM
1101 else if (sc->fmt->hexret)
1102 fprintf(trace->output, ") = %#x", ret);
ba3d7dee 1103 else
da3c9a44 1104 goto signed_print;
ba3d7dee 1105
c24ff998 1106 fputc('\n', trace->output);
ae9ed035 1107out:
752fde44
ACM
1108 ttrace->entry_pending = false;
1109
ba3d7dee
ACM
1110 return 0;
1111}
1112
1302d88e
ACM
1113static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1114 struct perf_sample *sample)
1115{
1116 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1117 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
314add6b
AH
1118 struct thread *thread = machine__findnew_thread(&trace->host,
1119 sample->pid,
1120 sample->tid);
c24ff998 1121 struct thread_trace *ttrace = thread__trace(thread, trace->output);
1302d88e
ACM
1122
1123 if (ttrace == NULL)
1124 goto out_dump;
1125
1126 ttrace->runtime_ms += runtime_ms;
1127 trace->runtime_ms += runtime_ms;
1128 return 0;
1129
1130out_dump:
c24ff998 1131 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
1302d88e
ACM
1132 evsel->name,
1133 perf_evsel__strval(evsel, sample, "comm"),
1134 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1135 runtime,
1136 perf_evsel__intval(evsel, sample, "vruntime"));
1137 return 0;
1138}
1139
bdc89661
DA
1140static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1141{
1142 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1143 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1144 return false;
1145
1146 if (trace->pid_list || trace->tid_list)
1147 return true;
1148
1149 return false;
1150}
1151
6810fc91
DA
1152static int trace__process_sample(struct perf_tool *tool,
1153 union perf_event *event __maybe_unused,
1154 struct perf_sample *sample,
1155 struct perf_evsel *evsel,
1156 struct machine *machine __maybe_unused)
1157{
1158 struct trace *trace = container_of(tool, struct trace, tool);
1159 int err = 0;
1160
1161 tracepoint_handler handler = evsel->handler.func;
1162
bdc89661
DA
1163 if (skip_sample(trace, sample))
1164 return 0;
1165
4bb09192 1166 if (!trace->full_time && trace->base_time == 0)
6810fc91
DA
1167 trace->base_time = sample->time;
1168
1169 if (handler)
1170 handler(trace, evsel, sample);
1171
1172 return err;
1173}
1174
1175static bool
1176perf_session__has_tp(struct perf_session *session, const char *name)
1177{
1178 struct perf_evsel *evsel;
1179
1180 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1181
1182 return evsel != NULL;
1183}
1184
bdc89661
DA
1185static int parse_target_str(struct trace *trace)
1186{
1187 if (trace->opts.target.pid) {
1188 trace->pid_list = intlist__new(trace->opts.target.pid);
1189 if (trace->pid_list == NULL) {
1190 pr_err("Error parsing process id string\n");
1191 return -EINVAL;
1192 }
1193 }
1194
1195 if (trace->opts.target.tid) {
1196 trace->tid_list = intlist__new(trace->opts.target.tid);
1197 if (trace->tid_list == NULL) {
1198 pr_err("Error parsing thread id string\n");
1199 return -EINVAL;
1200 }
1201 }
1202
1203 return 0;
1204}
1205
f15eb531 1206static int trace__run(struct trace *trace, int argc, const char **argv)
514f1c67 1207{
334fe7a3 1208 struct perf_evlist *evlist = perf_evlist__new();
ba3d7dee 1209 struct perf_evsel *evsel;
efd5745e
ACM
1210 int err = -1, i;
1211 unsigned long before;
f15eb531 1212 const bool forks = argc > 0;
514f1c67
ACM
1213
1214 if (evlist == NULL) {
c24ff998 1215 fprintf(trace->output, "Not enough memory to run!\n");
514f1c67
ACM
1216 goto out;
1217 }
1218
39876e7d
ACM
1219 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1220 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
c24ff998 1221 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
514f1c67
ACM
1222 goto out_delete_evlist;
1223 }
1224
1302d88e
ACM
1225 if (trace->sched &&
1226 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1227 trace__sched_stat_runtime)) {
c24ff998 1228 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
1302d88e
ACM
1229 goto out_delete_evlist;
1230 }
1231
514f1c67
ACM
1232 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1233 if (err < 0) {
c24ff998 1234 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
514f1c67
ACM
1235 goto out_delete_evlist;
1236 }
1237
752fde44
ACM
1238 err = trace__symbols_init(trace, evlist);
1239 if (err < 0) {
c24ff998 1240 fprintf(trace->output, "Problems initializing symbol libraries!\n");
3beb0861 1241 goto out_delete_maps;
752fde44
ACM
1242 }
1243
f77a9518 1244 perf_evlist__config(evlist, &trace->opts);
514f1c67 1245
f15eb531
NK
1246 signal(SIGCHLD, sig_handler);
1247 signal(SIGINT, sig_handler);
1248
1249 if (forks) {
6ef73ec4 1250 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
55e162ea 1251 argv, false, false);
f15eb531 1252 if (err < 0) {
c24ff998 1253 fprintf(trace->output, "Couldn't run the workload!\n");
3beb0861 1254 goto out_delete_maps;
f15eb531
NK
1255 }
1256 }
1257
514f1c67
ACM
1258 err = perf_evlist__open(evlist);
1259 if (err < 0) {
c24ff998 1260 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
3beb0861 1261 goto out_delete_maps;
514f1c67
ACM
1262 }
1263
1264 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1265 if (err < 0) {
c24ff998 1266 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
3beb0861 1267 goto out_close_evlist;
514f1c67
ACM
1268 }
1269
1270 perf_evlist__enable(evlist);
f15eb531
NK
1271
1272 if (forks)
1273 perf_evlist__start_workload(evlist);
1274
752fde44 1275 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
514f1c67 1276again:
efd5745e 1277 before = trace->nr_events;
514f1c67
ACM
1278
1279 for (i = 0; i < evlist->nr_mmaps; i++) {
1280 union perf_event *event;
1281
1282 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1283 const u32 type = event->header.type;
ba3d7dee 1284 tracepoint_handler handler;
514f1c67 1285 struct perf_sample sample;
514f1c67 1286
efd5745e 1287 ++trace->nr_events;
514f1c67 1288
514f1c67
ACM
1289 err = perf_evlist__parse_sample(evlist, event, &sample);
1290 if (err) {
c24ff998 1291 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
514f1c67
ACM
1292 continue;
1293 }
1294
4bb09192 1295 if (!trace->full_time && trace->base_time == 0)
752fde44
ACM
1296 trace->base_time = sample.time;
1297
1298 if (type != PERF_RECORD_SAMPLE) {
c24ff998 1299 trace__process_event(trace, &trace->host, event);
752fde44
ACM
1300 continue;
1301 }
1302
514f1c67
ACM
1303 evsel = perf_evlist__id2evsel(evlist, sample.id);
1304 if (evsel == NULL) {
c24ff998 1305 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
514f1c67
ACM
1306 continue;
1307 }
1308
fc551f8d 1309 if (sample.raw_data == NULL) {
c24ff998 1310 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
fc551f8d
ACM
1311 perf_evsel__name(evsel), sample.tid,
1312 sample.cpu, sample.raw_size);
1313 continue;
1314 }
1315
ba3d7dee
ACM
1316 handler = evsel->handler.func;
1317 handler(trace, evsel, &sample);
20c5f10e
ACM
1318
1319 if (done)
1320 goto out_unmap_evlist;
514f1c67
ACM
1321 }
1322 }
1323
efd5745e 1324 if (trace->nr_events == before) {
f15eb531 1325 if (done)
3beb0861 1326 goto out_unmap_evlist;
f15eb531 1327
514f1c67 1328 poll(evlist->pollfd, evlist->nr_fds, -1);
f15eb531
NK
1329 }
1330
1331 if (done)
1332 perf_evlist__disable(evlist);
514f1c67
ACM
1333
1334 goto again;
1335
3beb0861
NK
1336out_unmap_evlist:
1337 perf_evlist__munmap(evlist);
1338out_close_evlist:
1339 perf_evlist__close(evlist);
1340out_delete_maps:
1341 perf_evlist__delete_maps(evlist);
514f1c67
ACM
1342out_delete_evlist:
1343 perf_evlist__delete(evlist);
1344out:
1345 return err;
1346}
1347
6810fc91
DA
1348static int trace__replay(struct trace *trace)
1349{
1350 const struct perf_evsel_str_handler handlers[] = {
1351 { "raw_syscalls:sys_enter", trace__sys_enter, },
1352 { "raw_syscalls:sys_exit", trace__sys_exit, },
1353 };
1354
1355 struct perf_session *session;
1356 int err = -1;
1357
1358 trace->tool.sample = trace__process_sample;
1359 trace->tool.mmap = perf_event__process_mmap;
384c671e 1360 trace->tool.mmap2 = perf_event__process_mmap2;
6810fc91
DA
1361 trace->tool.comm = perf_event__process_comm;
1362 trace->tool.exit = perf_event__process_exit;
1363 trace->tool.fork = perf_event__process_fork;
1364 trace->tool.attr = perf_event__process_attr;
1365 trace->tool.tracing_data = perf_event__process_tracing_data;
1366 trace->tool.build_id = perf_event__process_build_id;
1367
1368 trace->tool.ordered_samples = true;
1369 trace->tool.ordering_requires_timestamps = true;
1370
1371 /* add tid to output */
1372 trace->multiple_threads = true;
1373
1374 if (symbol__init() < 0)
1375 return -1;
1376
1377 session = perf_session__new(input_name, O_RDONLY, 0, false,
1378 &trace->tool);
1379 if (session == NULL)
1380 return -ENOMEM;
1381
1382 err = perf_session__set_tracepoints_handlers(session, handlers);
1383 if (err)
1384 goto out;
1385
1386 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1387 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1388 goto out;
1389 }
1390
1391 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1392 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1393 goto out;
1394 }
1395
bdc89661
DA
1396 err = parse_target_str(trace);
1397 if (err != 0)
1398 goto out;
1399
6810fc91
DA
1400 setup_pager();
1401
1402 err = perf_session__process_events(session, &trace->tool);
1403 if (err)
1404 pr_err("Failed to process events, error %d", err);
1405
1406out:
1407 perf_session__delete(session);
1408
1409 return err;
1410}
1411
1302d88e
ACM
1412static size_t trace__fprintf_threads_header(FILE *fp)
1413{
1414 size_t printed;
1415
1416 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1417 printed += fprintf(fp," __) Summary of events (__\n\n");
1418 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1419 printed += fprintf(fp," _____________________________________________________________________\n\n");
1420
1421 return printed;
1422}
1423
1424static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1425{
1426 size_t printed = trace__fprintf_threads_header(fp);
1427 struct rb_node *nd;
1428
1429 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
1430 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1431 struct thread_trace *ttrace = thread->priv;
1432 const char *color;
1433 double ratio;
1434
1435 if (ttrace == NULL)
1436 continue;
1437
1438 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1439
1440 color = PERF_COLOR_NORMAL;
1441 if (ratio > 50.0)
1442 color = PERF_COLOR_RED;
1443 else if (ratio > 25.0)
1444 color = PERF_COLOR_GREEN;
1445 else if (ratio > 5.0)
1446 color = PERF_COLOR_YELLOW;
1447
1448 printed += color_fprintf(fp, color, "%20s", thread->comm);
38051234 1449 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
1302d88e
ACM
1450 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1451 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1452 }
1453
1454 return printed;
1455}
1456
ae9ed035
ACM
1457static int trace__set_duration(const struct option *opt, const char *str,
1458 int unset __maybe_unused)
1459{
1460 struct trace *trace = opt->value;
1461
1462 trace->duration_filter = atof(str);
1463 return 0;
1464}
1465
c24ff998
ACM
1466static int trace__open_output(struct trace *trace, const char *filename)
1467{
1468 struct stat st;
1469
1470 if (!stat(filename, &st) && st.st_size) {
1471 char oldname[PATH_MAX];
1472
1473 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1474 unlink(oldname);
1475 rename(filename, oldname);
1476 }
1477
1478 trace->output = fopen(filename, "w");
1479
1480 return trace->output == NULL ? -errno : 0;
1481}
1482
514f1c67
ACM
1483int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1484{
1485 const char * const trace_usage[] = {
f15eb531
NK
1486 "perf trace [<options>] [<command>]",
1487 "perf trace [<options>] -- <command> [<options>]",
514f1c67
ACM
1488 NULL
1489 };
1490 struct trace trace = {
1491 .audit_machine = audit_detect_machine(),
1492 .syscalls = {
1493 . max = -1,
1494 },
1495 .opts = {
1496 .target = {
1497 .uid = UINT_MAX,
1498 .uses_mmap = true,
1499 },
1500 .user_freq = UINT_MAX,
1501 .user_interval = ULLONG_MAX,
1502 .no_delay = true,
1503 .mmap_pages = 1024,
1504 },
c24ff998 1505 .output = stdout,
514f1c67 1506 };
c24ff998 1507 const char *output_name = NULL;
2ae3a312 1508 const char *ev_qualifier_str = NULL;
514f1c67 1509 const struct option trace_options[] = {
2ae3a312
ACM
1510 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1511 "list of events to trace"),
c24ff998 1512 OPT_STRING('o', "output", &output_name, "file", "output file name"),
6810fc91 1513 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
514f1c67
ACM
1514 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1515 "trace events on existing process id"),
ac9be8ee 1516 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
514f1c67 1517 "trace events on existing thread id"),
ac9be8ee 1518 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
514f1c67 1519 "system-wide collection from all CPUs"),
ac9be8ee 1520 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
514f1c67 1521 "list of cpus to monitor"),
6810fc91 1522 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
514f1c67 1523 "child tasks do not inherit counters"),
ac9be8ee 1524 OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages,
514f1c67 1525 "number of mmap data pages"),
ac9be8ee 1526 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
514f1c67 1527 "user to profile"),
ae9ed035
ACM
1528 OPT_CALLBACK(0, "duration", &trace, "float",
1529 "show only events with duration > N.M ms",
1530 trace__set_duration),
1302d88e 1531 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
7c304ee0 1532 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
4bb09192
DA
1533 OPT_BOOLEAN('T', "time", &trace.full_time,
1534 "Show full timestamp, not time relative to first start"),
514f1c67
ACM
1535 OPT_END()
1536 };
1537 int err;
32caf0d1 1538 char bf[BUFSIZ];
514f1c67
ACM
1539
1540 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
514f1c67 1541
c24ff998
ACM
1542 if (output_name != NULL) {
1543 err = trace__open_output(&trace, output_name);
1544 if (err < 0) {
1545 perror("failed to create output file");
1546 goto out;
1547 }
1548 }
1549
2ae3a312 1550 if (ev_qualifier_str != NULL) {
b059efdf
ACM
1551 const char *s = ev_qualifier_str;
1552
1553 trace.not_ev_qualifier = *s == '!';
1554 if (trace.not_ev_qualifier)
1555 ++s;
1556 trace.ev_qualifier = strlist__new(true, s);
2ae3a312 1557 if (trace.ev_qualifier == NULL) {
c24ff998
ACM
1558 fputs("Not enough memory to parse event qualifier",
1559 trace.output);
1560 err = -ENOMEM;
1561 goto out_close;
2ae3a312
ACM
1562 }
1563 }
1564
32caf0d1
NK
1565 err = perf_target__validate(&trace.opts.target);
1566 if (err) {
1567 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
1568 fprintf(trace.output, "%s", bf);
1569 goto out_close;
32caf0d1
NK
1570 }
1571
514f1c67
ACM
1572 err = perf_target__parse_uid(&trace.opts.target);
1573 if (err) {
514f1c67 1574 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
1575 fprintf(trace.output, "%s", bf);
1576 goto out_close;
514f1c67
ACM
1577 }
1578
f15eb531 1579 if (!argc && perf_target__none(&trace.opts.target))
ee76120e
NK
1580 trace.opts.target.system_wide = true;
1581
6810fc91
DA
1582 if (input_name)
1583 err = trace__replay(&trace);
1584 else
1585 err = trace__run(&trace, argc, argv);
1302d88e
ACM
1586
1587 if (trace.sched && !err)
c24ff998 1588 trace__fprintf_thread_summary(&trace, trace.output);
1302d88e 1589
c24ff998
ACM
1590out_close:
1591 if (output_name != NULL)
1592 fclose(trace.output);
1593out:
1302d88e 1594 return err;
514f1c67 1595}
This page took 0.126801 seconds and 5 git commands to generate.