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