perf symbols: Make a separate function to parse /proc/modules
[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
5e2485b1
DA
1504static int trace__record(int argc, const char **argv)
1505{
1506 unsigned int rec_argc, i, j;
1507 const char **rec_argv;
1508 const char * const record_args[] = {
1509 "record",
1510 "-R",
1511 "-m", "1024",
1512 "-c", "1",
1513 "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit",
1514 };
1515
1516 rec_argc = ARRAY_SIZE(record_args) + argc;
1517 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1518
1519 if (rec_argv == NULL)
1520 return -ENOMEM;
1521
1522 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1523 rec_argv[i] = record_args[i];
1524
1525 for (j = 0; j < (unsigned int)argc; j++, i++)
1526 rec_argv[i] = argv[j];
1527
1528 return cmd_record(i, rec_argv, NULL);
1529}
1530
f15eb531 1531static int trace__run(struct trace *trace, int argc, const char **argv)
514f1c67 1532{
334fe7a3 1533 struct perf_evlist *evlist = perf_evlist__new();
ba3d7dee 1534 struct perf_evsel *evsel;
efd5745e
ACM
1535 int err = -1, i;
1536 unsigned long before;
f15eb531 1537 const bool forks = argc > 0;
514f1c67 1538
75b757ca
ACM
1539 trace->live = true;
1540
514f1c67 1541 if (evlist == NULL) {
c24ff998 1542 fprintf(trace->output, "Not enough memory to run!\n");
514f1c67
ACM
1543 goto out;
1544 }
1545
39876e7d
ACM
1546 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1547 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
c24ff998 1548 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
514f1c67
ACM
1549 goto out_delete_evlist;
1550 }
1551
1302d88e
ACM
1552 if (trace->sched &&
1553 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1554 trace__sched_stat_runtime)) {
c24ff998 1555 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
1302d88e
ACM
1556 goto out_delete_evlist;
1557 }
1558
514f1c67
ACM
1559 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1560 if (err < 0) {
c24ff998 1561 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
514f1c67
ACM
1562 goto out_delete_evlist;
1563 }
1564
752fde44
ACM
1565 err = trace__symbols_init(trace, evlist);
1566 if (err < 0) {
c24ff998 1567 fprintf(trace->output, "Problems initializing symbol libraries!\n");
3beb0861 1568 goto out_delete_maps;
752fde44
ACM
1569 }
1570
f77a9518 1571 perf_evlist__config(evlist, &trace->opts);
514f1c67 1572
f15eb531
NK
1573 signal(SIGCHLD, sig_handler);
1574 signal(SIGINT, sig_handler);
1575
1576 if (forks) {
6ef73ec4 1577 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
55e162ea 1578 argv, false, false);
f15eb531 1579 if (err < 0) {
c24ff998 1580 fprintf(trace->output, "Couldn't run the workload!\n");
3beb0861 1581 goto out_delete_maps;
f15eb531
NK
1582 }
1583 }
1584
514f1c67
ACM
1585 err = perf_evlist__open(evlist);
1586 if (err < 0) {
c24ff998 1587 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
3beb0861 1588 goto out_delete_maps;
514f1c67
ACM
1589 }
1590
1591 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1592 if (err < 0) {
c24ff998 1593 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
3beb0861 1594 goto out_close_evlist;
514f1c67
ACM
1595 }
1596
1597 perf_evlist__enable(evlist);
f15eb531
NK
1598
1599 if (forks)
1600 perf_evlist__start_workload(evlist);
1601
752fde44 1602 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
514f1c67 1603again:
efd5745e 1604 before = trace->nr_events;
514f1c67
ACM
1605
1606 for (i = 0; i < evlist->nr_mmaps; i++) {
1607 union perf_event *event;
1608
1609 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1610 const u32 type = event->header.type;
ba3d7dee 1611 tracepoint_handler handler;
514f1c67 1612 struct perf_sample sample;
514f1c67 1613
efd5745e 1614 ++trace->nr_events;
514f1c67 1615
514f1c67
ACM
1616 err = perf_evlist__parse_sample(evlist, event, &sample);
1617 if (err) {
c24ff998 1618 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
514f1c67
ACM
1619 continue;
1620 }
1621
4bb09192 1622 if (!trace->full_time && trace->base_time == 0)
752fde44
ACM
1623 trace->base_time = sample.time;
1624
1625 if (type != PERF_RECORD_SAMPLE) {
8fb598e5 1626 trace__process_event(trace, trace->host, event);
752fde44
ACM
1627 continue;
1628 }
1629
514f1c67
ACM
1630 evsel = perf_evlist__id2evsel(evlist, sample.id);
1631 if (evsel == NULL) {
c24ff998 1632 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
514f1c67
ACM
1633 continue;
1634 }
1635
fc551f8d 1636 if (sample.raw_data == NULL) {
c24ff998 1637 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
fc551f8d
ACM
1638 perf_evsel__name(evsel), sample.tid,
1639 sample.cpu, sample.raw_size);
1640 continue;
1641 }
1642
ba3d7dee
ACM
1643 handler = evsel->handler.func;
1644 handler(trace, evsel, &sample);
20c5f10e
ACM
1645
1646 if (done)
1647 goto out_unmap_evlist;
514f1c67
ACM
1648 }
1649 }
1650
efd5745e 1651 if (trace->nr_events == before) {
f15eb531 1652 if (done)
3beb0861 1653 goto out_unmap_evlist;
f15eb531 1654
514f1c67 1655 poll(evlist->pollfd, evlist->nr_fds, -1);
f15eb531
NK
1656 }
1657
1658 if (done)
1659 perf_evlist__disable(evlist);
514f1c67
ACM
1660
1661 goto again;
1662
3beb0861
NK
1663out_unmap_evlist:
1664 perf_evlist__munmap(evlist);
1665out_close_evlist:
1666 perf_evlist__close(evlist);
1667out_delete_maps:
1668 perf_evlist__delete_maps(evlist);
514f1c67
ACM
1669out_delete_evlist:
1670 perf_evlist__delete(evlist);
1671out:
75b757ca 1672 trace->live = false;
514f1c67
ACM
1673 return err;
1674}
1675
6810fc91
DA
1676static int trace__replay(struct trace *trace)
1677{
1678 const struct perf_evsel_str_handler handlers[] = {
1679 { "raw_syscalls:sys_enter", trace__sys_enter, },
1680 { "raw_syscalls:sys_exit", trace__sys_exit, },
1681 };
1682
1683 struct perf_session *session;
1684 int err = -1;
1685
1686 trace->tool.sample = trace__process_sample;
1687 trace->tool.mmap = perf_event__process_mmap;
384c671e 1688 trace->tool.mmap2 = perf_event__process_mmap2;
6810fc91
DA
1689 trace->tool.comm = perf_event__process_comm;
1690 trace->tool.exit = perf_event__process_exit;
1691 trace->tool.fork = perf_event__process_fork;
1692 trace->tool.attr = perf_event__process_attr;
1693 trace->tool.tracing_data = perf_event__process_tracing_data;
1694 trace->tool.build_id = perf_event__process_build_id;
1695
1696 trace->tool.ordered_samples = true;
1697 trace->tool.ordering_requires_timestamps = true;
1698
1699 /* add tid to output */
1700 trace->multiple_threads = true;
1701
1702 if (symbol__init() < 0)
1703 return -1;
1704
1705 session = perf_session__new(input_name, O_RDONLY, 0, false,
1706 &trace->tool);
1707 if (session == NULL)
1708 return -ENOMEM;
1709
8fb598e5
DA
1710 trace->host = &session->machines.host;
1711
6810fc91
DA
1712 err = perf_session__set_tracepoints_handlers(session, handlers);
1713 if (err)
1714 goto out;
1715
1716 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1717 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1718 goto out;
1719 }
1720
1721 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1722 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1723 goto out;
1724 }
1725
bdc89661
DA
1726 err = parse_target_str(trace);
1727 if (err != 0)
1728 goto out;
1729
6810fc91
DA
1730 setup_pager();
1731
1732 err = perf_session__process_events(session, &trace->tool);
1733 if (err)
1734 pr_err("Failed to process events, error %d", err);
1735
1736out:
1737 perf_session__delete(session);
1738
1739 return err;
1740}
1741
1302d88e
ACM
1742static size_t trace__fprintf_threads_header(FILE *fp)
1743{
1744 size_t printed;
1745
1746 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1747 printed += fprintf(fp," __) Summary of events (__\n\n");
1748 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1749 printed += fprintf(fp," _____________________________________________________________________\n\n");
1750
1751 return printed;
1752}
1753
896cbb56
DA
1754/* struct used to pass data to per-thread function */
1755struct summary_data {
1756 FILE *fp;
1757 struct trace *trace;
1758 size_t printed;
1759};
1760
1761static int trace__fprintf_one_thread(struct thread *thread, void *priv)
1762{
1763 struct summary_data *data = priv;
1764 FILE *fp = data->fp;
1765 size_t printed = data->printed;
1766 struct trace *trace = data->trace;
1767 struct thread_trace *ttrace = thread->priv;
1768 const char *color;
1769 double ratio;
1770
1771 if (ttrace == NULL)
1772 return 0;
1773
1774 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1775
1776 color = PERF_COLOR_NORMAL;
1777 if (ratio > 50.0)
1778 color = PERF_COLOR_RED;
1779 else if (ratio > 25.0)
1780 color = PERF_COLOR_GREEN;
1781 else if (ratio > 5.0)
1782 color = PERF_COLOR_YELLOW;
1783
1784 printed += color_fprintf(fp, color, "%20s", thread->comm);
1785 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
1786 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1787 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1788
1789 data->printed += printed;
1790
1791 return 0;
1792}
1793
1302d88e
ACM
1794static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1795{
896cbb56
DA
1796 struct summary_data data = {
1797 .fp = fp,
1798 .trace = trace
1799 };
1800 data.printed = trace__fprintf_threads_header(fp);
1302d88e 1801
896cbb56
DA
1802 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
1803
1804 return data.printed;
1302d88e
ACM
1805}
1806
ae9ed035
ACM
1807static int trace__set_duration(const struct option *opt, const char *str,
1808 int unset __maybe_unused)
1809{
1810 struct trace *trace = opt->value;
1811
1812 trace->duration_filter = atof(str);
1813 return 0;
1814}
1815
c24ff998
ACM
1816static int trace__open_output(struct trace *trace, const char *filename)
1817{
1818 struct stat st;
1819
1820 if (!stat(filename, &st) && st.st_size) {
1821 char oldname[PATH_MAX];
1822
1823 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1824 unlink(oldname);
1825 rename(filename, oldname);
1826 }
1827
1828 trace->output = fopen(filename, "w");
1829
1830 return trace->output == NULL ? -errno : 0;
1831}
1832
514f1c67
ACM
1833int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1834{
1835 const char * const trace_usage[] = {
f15eb531
NK
1836 "perf trace [<options>] [<command>]",
1837 "perf trace [<options>] -- <command> [<options>]",
5e2485b1
DA
1838 "perf trace record [<options>] [<command>]",
1839 "perf trace record [<options>] -- <command> [<options>]",
514f1c67
ACM
1840 NULL
1841 };
1842 struct trace trace = {
1843 .audit_machine = audit_detect_machine(),
1844 .syscalls = {
1845 . max = -1,
1846 },
1847 .opts = {
1848 .target = {
1849 .uid = UINT_MAX,
1850 .uses_mmap = true,
1851 },
1852 .user_freq = UINT_MAX,
1853 .user_interval = ULLONG_MAX,
1854 .no_delay = true,
1855 .mmap_pages = 1024,
1856 },
c24ff998 1857 .output = stdout,
50c95cbd 1858 .show_comm = true,
514f1c67 1859 };
c24ff998 1860 const char *output_name = NULL;
2ae3a312 1861 const char *ev_qualifier_str = NULL;
514f1c67 1862 const struct option trace_options[] = {
50c95cbd
ACM
1863 OPT_BOOLEAN(0, "comm", &trace.show_comm,
1864 "show the thread COMM next to its id"),
2ae3a312
ACM
1865 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1866 "list of events to trace"),
c24ff998 1867 OPT_STRING('o', "output", &output_name, "file", "output file name"),
6810fc91 1868 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
514f1c67
ACM
1869 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1870 "trace events on existing process id"),
ac9be8ee 1871 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
514f1c67 1872 "trace events on existing thread id"),
ac9be8ee 1873 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
514f1c67 1874 "system-wide collection from all CPUs"),
ac9be8ee 1875 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
514f1c67 1876 "list of cpus to monitor"),
6810fc91 1877 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
514f1c67 1878 "child tasks do not inherit counters"),
994a1f78
JO
1879 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
1880 "number of mmap data pages",
1881 perf_evlist__parse_mmap_pages),
ac9be8ee 1882 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
514f1c67 1883 "user to profile"),
ae9ed035
ACM
1884 OPT_CALLBACK(0, "duration", &trace, "float",
1885 "show only events with duration > N.M ms",
1886 trace__set_duration),
1302d88e 1887 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
7c304ee0 1888 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
4bb09192
DA
1889 OPT_BOOLEAN('T', "time", &trace.full_time,
1890 "Show full timestamp, not time relative to first start"),
514f1c67
ACM
1891 OPT_END()
1892 };
1893 int err;
32caf0d1 1894 char bf[BUFSIZ];
514f1c67 1895
5e2485b1
DA
1896 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
1897 return trace__record(argc-2, &argv[2]);
1898
514f1c67 1899 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
514f1c67 1900
c24ff998
ACM
1901 if (output_name != NULL) {
1902 err = trace__open_output(&trace, output_name);
1903 if (err < 0) {
1904 perror("failed to create output file");
1905 goto out;
1906 }
1907 }
1908
2ae3a312 1909 if (ev_qualifier_str != NULL) {
b059efdf
ACM
1910 const char *s = ev_qualifier_str;
1911
1912 trace.not_ev_qualifier = *s == '!';
1913 if (trace.not_ev_qualifier)
1914 ++s;
1915 trace.ev_qualifier = strlist__new(true, s);
2ae3a312 1916 if (trace.ev_qualifier == NULL) {
c24ff998
ACM
1917 fputs("Not enough memory to parse event qualifier",
1918 trace.output);
1919 err = -ENOMEM;
1920 goto out_close;
2ae3a312
ACM
1921 }
1922 }
1923
32caf0d1
NK
1924 err = perf_target__validate(&trace.opts.target);
1925 if (err) {
1926 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
1927 fprintf(trace.output, "%s", bf);
1928 goto out_close;
32caf0d1
NK
1929 }
1930
514f1c67
ACM
1931 err = perf_target__parse_uid(&trace.opts.target);
1932 if (err) {
514f1c67 1933 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
1934 fprintf(trace.output, "%s", bf);
1935 goto out_close;
514f1c67
ACM
1936 }
1937
f15eb531 1938 if (!argc && perf_target__none(&trace.opts.target))
ee76120e
NK
1939 trace.opts.target.system_wide = true;
1940
6810fc91
DA
1941 if (input_name)
1942 err = trace__replay(&trace);
1943 else
1944 err = trace__run(&trace, argc, argv);
1302d88e
ACM
1945
1946 if (trace.sched && !err)
c24ff998 1947 trace__fprintf_thread_summary(&trace, trace.output);
1302d88e 1948
c24ff998
ACM
1949out_close:
1950 if (output_name != NULL)
1951 fclose(trace.output);
1952out:
1302d88e 1953 return err;
514f1c67 1954}
This page took 0.164303 seconds and 5 git commands to generate.