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