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