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