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