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