perf trace: Remove duplicate mmap entry in syscall_fmts array
[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
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
752fde44 821 printed += scnprintf(bf + printed, size - printed,
13d4ff3e 822 "%s%s: ", printed ? ", " : "", field->name);
01533e97
ACM
823 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
824 arg.val = args[arg.idx];
1f115cb7
ACM
825 if (sc->arg_parm)
826 arg.parm = sc->arg_parm[arg.idx];
01533e97
ACM
827 printed += sc->arg_scnprintf[arg.idx](bf + printed,
828 size - printed, &arg);
6e7eeb51 829 } else {
13d4ff3e 830 printed += scnprintf(bf + printed, size - printed,
01533e97 831 "%ld", args[arg.idx]);
6e7eeb51 832 }
514f1c67
ACM
833 }
834 } else {
01533e97
ACM
835 int i = 0;
836
514f1c67 837 while (i < 6) {
752fde44
ACM
838 printed += scnprintf(bf + printed, size - printed,
839 "%sarg%d: %ld",
840 printed ? ", " : "", i, args[i]);
514f1c67
ACM
841 ++i;
842 }
843 }
844
845 return printed;
846}
847
ba3d7dee
ACM
848typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
849 struct perf_sample *sample);
850
851static struct syscall *trace__syscall_info(struct trace *trace,
852 struct perf_evsel *evsel,
853 struct perf_sample *sample)
854{
855 int id = perf_evsel__intval(evsel, sample, "id");
856
857 if (id < 0) {
adaa18bf
ACM
858
859 /*
860 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
861 * before that, leaving at a higher verbosity level till that is
862 * explained. Reproduced with plain ftrace with:
863 *
864 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
865 * grep "NR -1 " /t/trace_pipe
866 *
867 * After generating some load on the machine.
868 */
869 if (verbose > 1) {
870 static u64 n;
871 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
872 id, perf_evsel__name(evsel), ++n);
873 }
ba3d7dee
ACM
874 return NULL;
875 }
876
877 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
878 trace__read_syscall_info(trace, id))
879 goto out_cant_read;
880
881 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
882 goto out_cant_read;
883
884 return &trace->syscalls.table[id];
885
886out_cant_read:
7c304ee0
ACM
887 if (verbose) {
888 fprintf(trace->output, "Problems reading syscall %d", id);
889 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
890 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
891 fputs(" information\n", trace->output);
892 }
ba3d7dee
ACM
893 return NULL;
894}
895
896static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
897 struct perf_sample *sample)
898{
752fde44 899 char *msg;
ba3d7dee 900 void *args;
752fde44 901 size_t printed = 0;
2ae3a312 902 struct thread *thread;
ba3d7dee 903 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
2ae3a312
ACM
904 struct thread_trace *ttrace;
905
906 if (sc == NULL)
907 return -1;
ba3d7dee 908
2ae3a312
ACM
909 if (sc->filtered)
910 return 0;
911
314add6b
AH
912 thread = machine__findnew_thread(&trace->host, sample->pid,
913 sample->tid);
c24ff998 914 ttrace = thread__trace(thread, trace->output);
2ae3a312 915 if (ttrace == NULL)
ba3d7dee
ACM
916 return -1;
917
918 args = perf_evsel__rawptr(evsel, sample, "args");
919 if (args == NULL) {
c24ff998 920 fprintf(trace->output, "Problems reading syscall arguments\n");
ba3d7dee
ACM
921 return -1;
922 }
923
752fde44
ACM
924 ttrace = thread->priv;
925
926 if (ttrace->entry_str == NULL) {
927 ttrace->entry_str = malloc(1024);
928 if (!ttrace->entry_str)
929 return -1;
930 }
931
932 ttrace->entry_time = sample->time;
933 msg = ttrace->entry_str;
934 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
935
936 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
937
938 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
ae9ed035 939 if (!trace->duration_filter) {
c24ff998
ACM
940 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
941 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
ae9ed035 942 }
752fde44
ACM
943 } else
944 ttrace->entry_pending = true;
ba3d7dee
ACM
945
946 return 0;
947}
948
949static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
950 struct perf_sample *sample)
951{
952 int ret;
60c907ab 953 u64 duration = 0;
2ae3a312 954 struct thread *thread;
ba3d7dee 955 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
2ae3a312
ACM
956 struct thread_trace *ttrace;
957
958 if (sc == NULL)
959 return -1;
ba3d7dee 960
2ae3a312
ACM
961 if (sc->filtered)
962 return 0;
963
314add6b
AH
964 thread = machine__findnew_thread(&trace->host, sample->pid,
965 sample->tid);
c24ff998 966 ttrace = thread__trace(thread, trace->output);
2ae3a312 967 if (ttrace == NULL)
ba3d7dee
ACM
968 return -1;
969
970 ret = perf_evsel__intval(evsel, sample, "ret");
971
752fde44
ACM
972 ttrace = thread->priv;
973
974 ttrace->exit_time = sample->time;
975
ae9ed035 976 if (ttrace->entry_time) {
60c907ab 977 duration = sample->time - ttrace->entry_time;
ae9ed035
ACM
978 if (trace__filter_duration(trace, duration))
979 goto out;
980 } else if (trace->duration_filter)
981 goto out;
60c907ab 982
c24ff998 983 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
752fde44
ACM
984
985 if (ttrace->entry_pending) {
c24ff998 986 fprintf(trace->output, "%-70s", ttrace->entry_str);
752fde44 987 } else {
c24ff998
ACM
988 fprintf(trace->output, " ... [");
989 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
990 fprintf(trace->output, "]: %s()", sc->name);
752fde44
ACM
991 }
992
da3c9a44
ACM
993 if (sc->fmt == NULL) {
994signed_print:
995 fprintf(trace->output, ") = %d", ret);
996 } else if (ret < 0 && sc->fmt->errmsg) {
ba3d7dee
ACM
997 char bf[256];
998 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
999 *e = audit_errno_to_name(-ret);
1000
c24ff998 1001 fprintf(trace->output, ") = -1 %s %s", e, emsg);
da3c9a44 1002 } else if (ret == 0 && sc->fmt->timeout)
c24ff998 1003 fprintf(trace->output, ") = 0 Timeout");
04b34729
ACM
1004 else if (sc->fmt->hexret)
1005 fprintf(trace->output, ") = %#x", ret);
ba3d7dee 1006 else
da3c9a44 1007 goto signed_print;
ba3d7dee 1008
c24ff998 1009 fputc('\n', trace->output);
ae9ed035 1010out:
752fde44
ACM
1011 ttrace->entry_pending = false;
1012
ba3d7dee
ACM
1013 return 0;
1014}
1015
1302d88e
ACM
1016static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1017 struct perf_sample *sample)
1018{
1019 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1020 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
314add6b
AH
1021 struct thread *thread = machine__findnew_thread(&trace->host,
1022 sample->pid,
1023 sample->tid);
c24ff998 1024 struct thread_trace *ttrace = thread__trace(thread, trace->output);
1302d88e
ACM
1025
1026 if (ttrace == NULL)
1027 goto out_dump;
1028
1029 ttrace->runtime_ms += runtime_ms;
1030 trace->runtime_ms += runtime_ms;
1031 return 0;
1032
1033out_dump:
c24ff998 1034 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
1302d88e
ACM
1035 evsel->name,
1036 perf_evsel__strval(evsel, sample, "comm"),
1037 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1038 runtime,
1039 perf_evsel__intval(evsel, sample, "vruntime"));
1040 return 0;
1041}
1042
bdc89661
DA
1043static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1044{
1045 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1046 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1047 return false;
1048
1049 if (trace->pid_list || trace->tid_list)
1050 return true;
1051
1052 return false;
1053}
1054
6810fc91
DA
1055static int trace__process_sample(struct perf_tool *tool,
1056 union perf_event *event __maybe_unused,
1057 struct perf_sample *sample,
1058 struct perf_evsel *evsel,
1059 struct machine *machine __maybe_unused)
1060{
1061 struct trace *trace = container_of(tool, struct trace, tool);
1062 int err = 0;
1063
1064 tracepoint_handler handler = evsel->handler.func;
1065
bdc89661
DA
1066 if (skip_sample(trace, sample))
1067 return 0;
1068
4bb09192 1069 if (!trace->full_time && trace->base_time == 0)
6810fc91
DA
1070 trace->base_time = sample->time;
1071
1072 if (handler)
1073 handler(trace, evsel, sample);
1074
1075 return err;
1076}
1077
1078static bool
1079perf_session__has_tp(struct perf_session *session, const char *name)
1080{
1081 struct perf_evsel *evsel;
1082
1083 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1084
1085 return evsel != NULL;
1086}
1087
bdc89661
DA
1088static int parse_target_str(struct trace *trace)
1089{
1090 if (trace->opts.target.pid) {
1091 trace->pid_list = intlist__new(trace->opts.target.pid);
1092 if (trace->pid_list == NULL) {
1093 pr_err("Error parsing process id string\n");
1094 return -EINVAL;
1095 }
1096 }
1097
1098 if (trace->opts.target.tid) {
1099 trace->tid_list = intlist__new(trace->opts.target.tid);
1100 if (trace->tid_list == NULL) {
1101 pr_err("Error parsing thread id string\n");
1102 return -EINVAL;
1103 }
1104 }
1105
1106 return 0;
1107}
1108
f15eb531 1109static int trace__run(struct trace *trace, int argc, const char **argv)
514f1c67 1110{
334fe7a3 1111 struct perf_evlist *evlist = perf_evlist__new();
ba3d7dee 1112 struct perf_evsel *evsel;
efd5745e
ACM
1113 int err = -1, i;
1114 unsigned long before;
f15eb531 1115 const bool forks = argc > 0;
514f1c67
ACM
1116
1117 if (evlist == NULL) {
c24ff998 1118 fprintf(trace->output, "Not enough memory to run!\n");
514f1c67
ACM
1119 goto out;
1120 }
1121
39876e7d
ACM
1122 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1123 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
c24ff998 1124 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
514f1c67
ACM
1125 goto out_delete_evlist;
1126 }
1127
1302d88e
ACM
1128 if (trace->sched &&
1129 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1130 trace__sched_stat_runtime)) {
c24ff998 1131 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
1302d88e
ACM
1132 goto out_delete_evlist;
1133 }
1134
514f1c67
ACM
1135 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1136 if (err < 0) {
c24ff998 1137 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
514f1c67
ACM
1138 goto out_delete_evlist;
1139 }
1140
752fde44
ACM
1141 err = trace__symbols_init(trace, evlist);
1142 if (err < 0) {
c24ff998 1143 fprintf(trace->output, "Problems initializing symbol libraries!\n");
3beb0861 1144 goto out_delete_maps;
752fde44
ACM
1145 }
1146
f77a9518 1147 perf_evlist__config(evlist, &trace->opts);
514f1c67 1148
f15eb531
NK
1149 signal(SIGCHLD, sig_handler);
1150 signal(SIGINT, sig_handler);
1151
1152 if (forks) {
6ef73ec4 1153 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
55e162ea 1154 argv, false, false);
f15eb531 1155 if (err < 0) {
c24ff998 1156 fprintf(trace->output, "Couldn't run the workload!\n");
3beb0861 1157 goto out_delete_maps;
f15eb531
NK
1158 }
1159 }
1160
514f1c67
ACM
1161 err = perf_evlist__open(evlist);
1162 if (err < 0) {
c24ff998 1163 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
3beb0861 1164 goto out_delete_maps;
514f1c67
ACM
1165 }
1166
1167 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1168 if (err < 0) {
c24ff998 1169 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
3beb0861 1170 goto out_close_evlist;
514f1c67
ACM
1171 }
1172
1173 perf_evlist__enable(evlist);
f15eb531
NK
1174
1175 if (forks)
1176 perf_evlist__start_workload(evlist);
1177
752fde44 1178 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
514f1c67 1179again:
efd5745e 1180 before = trace->nr_events;
514f1c67
ACM
1181
1182 for (i = 0; i < evlist->nr_mmaps; i++) {
1183 union perf_event *event;
1184
1185 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1186 const u32 type = event->header.type;
ba3d7dee 1187 tracepoint_handler handler;
514f1c67 1188 struct perf_sample sample;
514f1c67 1189
efd5745e 1190 ++trace->nr_events;
514f1c67 1191
514f1c67
ACM
1192 err = perf_evlist__parse_sample(evlist, event, &sample);
1193 if (err) {
c24ff998 1194 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
514f1c67
ACM
1195 continue;
1196 }
1197
4bb09192 1198 if (!trace->full_time && trace->base_time == 0)
752fde44
ACM
1199 trace->base_time = sample.time;
1200
1201 if (type != PERF_RECORD_SAMPLE) {
c24ff998 1202 trace__process_event(trace, &trace->host, event);
752fde44
ACM
1203 continue;
1204 }
1205
514f1c67
ACM
1206 evsel = perf_evlist__id2evsel(evlist, sample.id);
1207 if (evsel == NULL) {
c24ff998 1208 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
514f1c67
ACM
1209 continue;
1210 }
1211
fc551f8d 1212 if (sample.raw_data == NULL) {
c24ff998 1213 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
fc551f8d
ACM
1214 perf_evsel__name(evsel), sample.tid,
1215 sample.cpu, sample.raw_size);
1216 continue;
1217 }
1218
ba3d7dee
ACM
1219 handler = evsel->handler.func;
1220 handler(trace, evsel, &sample);
20c5f10e
ACM
1221
1222 if (done)
1223 goto out_unmap_evlist;
514f1c67
ACM
1224 }
1225 }
1226
efd5745e 1227 if (trace->nr_events == before) {
f15eb531 1228 if (done)
3beb0861 1229 goto out_unmap_evlist;
f15eb531 1230
514f1c67 1231 poll(evlist->pollfd, evlist->nr_fds, -1);
f15eb531
NK
1232 }
1233
1234 if (done)
1235 perf_evlist__disable(evlist);
514f1c67
ACM
1236
1237 goto again;
1238
3beb0861
NK
1239out_unmap_evlist:
1240 perf_evlist__munmap(evlist);
1241out_close_evlist:
1242 perf_evlist__close(evlist);
1243out_delete_maps:
1244 perf_evlist__delete_maps(evlist);
514f1c67
ACM
1245out_delete_evlist:
1246 perf_evlist__delete(evlist);
1247out:
1248 return err;
1249}
1250
6810fc91
DA
1251static int trace__replay(struct trace *trace)
1252{
1253 const struct perf_evsel_str_handler handlers[] = {
1254 { "raw_syscalls:sys_enter", trace__sys_enter, },
1255 { "raw_syscalls:sys_exit", trace__sys_exit, },
1256 };
1257
1258 struct perf_session *session;
1259 int err = -1;
1260
1261 trace->tool.sample = trace__process_sample;
1262 trace->tool.mmap = perf_event__process_mmap;
384c671e 1263 trace->tool.mmap2 = perf_event__process_mmap2;
6810fc91
DA
1264 trace->tool.comm = perf_event__process_comm;
1265 trace->tool.exit = perf_event__process_exit;
1266 trace->tool.fork = perf_event__process_fork;
1267 trace->tool.attr = perf_event__process_attr;
1268 trace->tool.tracing_data = perf_event__process_tracing_data;
1269 trace->tool.build_id = perf_event__process_build_id;
1270
1271 trace->tool.ordered_samples = true;
1272 trace->tool.ordering_requires_timestamps = true;
1273
1274 /* add tid to output */
1275 trace->multiple_threads = true;
1276
1277 if (symbol__init() < 0)
1278 return -1;
1279
1280 session = perf_session__new(input_name, O_RDONLY, 0, false,
1281 &trace->tool);
1282 if (session == NULL)
1283 return -ENOMEM;
1284
1285 err = perf_session__set_tracepoints_handlers(session, handlers);
1286 if (err)
1287 goto out;
1288
1289 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1290 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1291 goto out;
1292 }
1293
1294 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1295 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1296 goto out;
1297 }
1298
bdc89661
DA
1299 err = parse_target_str(trace);
1300 if (err != 0)
1301 goto out;
1302
6810fc91
DA
1303 setup_pager();
1304
1305 err = perf_session__process_events(session, &trace->tool);
1306 if (err)
1307 pr_err("Failed to process events, error %d", err);
1308
1309out:
1310 perf_session__delete(session);
1311
1312 return err;
1313}
1314
1302d88e
ACM
1315static size_t trace__fprintf_threads_header(FILE *fp)
1316{
1317 size_t printed;
1318
1319 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1320 printed += fprintf(fp," __) Summary of events (__\n\n");
1321 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1322 printed += fprintf(fp," _____________________________________________________________________\n\n");
1323
1324 return printed;
1325}
1326
1327static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1328{
1329 size_t printed = trace__fprintf_threads_header(fp);
1330 struct rb_node *nd;
1331
1332 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
1333 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1334 struct thread_trace *ttrace = thread->priv;
1335 const char *color;
1336 double ratio;
1337
1338 if (ttrace == NULL)
1339 continue;
1340
1341 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1342
1343 color = PERF_COLOR_NORMAL;
1344 if (ratio > 50.0)
1345 color = PERF_COLOR_RED;
1346 else if (ratio > 25.0)
1347 color = PERF_COLOR_GREEN;
1348 else if (ratio > 5.0)
1349 color = PERF_COLOR_YELLOW;
1350
1351 printed += color_fprintf(fp, color, "%20s", thread->comm);
38051234 1352 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
1302d88e
ACM
1353 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1354 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1355 }
1356
1357 return printed;
1358}
1359
ae9ed035
ACM
1360static int trace__set_duration(const struct option *opt, const char *str,
1361 int unset __maybe_unused)
1362{
1363 struct trace *trace = opt->value;
1364
1365 trace->duration_filter = atof(str);
1366 return 0;
1367}
1368
c24ff998
ACM
1369static int trace__open_output(struct trace *trace, const char *filename)
1370{
1371 struct stat st;
1372
1373 if (!stat(filename, &st) && st.st_size) {
1374 char oldname[PATH_MAX];
1375
1376 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1377 unlink(oldname);
1378 rename(filename, oldname);
1379 }
1380
1381 trace->output = fopen(filename, "w");
1382
1383 return trace->output == NULL ? -errno : 0;
1384}
1385
514f1c67
ACM
1386int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1387{
1388 const char * const trace_usage[] = {
f15eb531
NK
1389 "perf trace [<options>] [<command>]",
1390 "perf trace [<options>] -- <command> [<options>]",
514f1c67
ACM
1391 NULL
1392 };
1393 struct trace trace = {
1394 .audit_machine = audit_detect_machine(),
1395 .syscalls = {
1396 . max = -1,
1397 },
1398 .opts = {
1399 .target = {
1400 .uid = UINT_MAX,
1401 .uses_mmap = true,
1402 },
1403 .user_freq = UINT_MAX,
1404 .user_interval = ULLONG_MAX,
1405 .no_delay = true,
1406 .mmap_pages = 1024,
1407 },
c24ff998 1408 .output = stdout,
514f1c67 1409 };
c24ff998 1410 const char *output_name = NULL;
2ae3a312 1411 const char *ev_qualifier_str = NULL;
514f1c67 1412 const struct option trace_options[] = {
2ae3a312
ACM
1413 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1414 "list of events to trace"),
c24ff998 1415 OPT_STRING('o', "output", &output_name, "file", "output file name"),
6810fc91 1416 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
514f1c67
ACM
1417 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1418 "trace events on existing process id"),
ac9be8ee 1419 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
514f1c67 1420 "trace events on existing thread id"),
ac9be8ee 1421 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
514f1c67 1422 "system-wide collection from all CPUs"),
ac9be8ee 1423 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
514f1c67 1424 "list of cpus to monitor"),
6810fc91 1425 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
514f1c67 1426 "child tasks do not inherit counters"),
ac9be8ee 1427 OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages,
514f1c67 1428 "number of mmap data pages"),
ac9be8ee 1429 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
514f1c67 1430 "user to profile"),
ae9ed035
ACM
1431 OPT_CALLBACK(0, "duration", &trace, "float",
1432 "show only events with duration > N.M ms",
1433 trace__set_duration),
1302d88e 1434 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
7c304ee0 1435 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
4bb09192
DA
1436 OPT_BOOLEAN('T', "time", &trace.full_time,
1437 "Show full timestamp, not time relative to first start"),
514f1c67
ACM
1438 OPT_END()
1439 };
1440 int err;
32caf0d1 1441 char bf[BUFSIZ];
514f1c67
ACM
1442
1443 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
514f1c67 1444
c24ff998
ACM
1445 if (output_name != NULL) {
1446 err = trace__open_output(&trace, output_name);
1447 if (err < 0) {
1448 perror("failed to create output file");
1449 goto out;
1450 }
1451 }
1452
2ae3a312 1453 if (ev_qualifier_str != NULL) {
b059efdf
ACM
1454 const char *s = ev_qualifier_str;
1455
1456 trace.not_ev_qualifier = *s == '!';
1457 if (trace.not_ev_qualifier)
1458 ++s;
1459 trace.ev_qualifier = strlist__new(true, s);
2ae3a312 1460 if (trace.ev_qualifier == NULL) {
c24ff998
ACM
1461 fputs("Not enough memory to parse event qualifier",
1462 trace.output);
1463 err = -ENOMEM;
1464 goto out_close;
2ae3a312
ACM
1465 }
1466 }
1467
32caf0d1
NK
1468 err = perf_target__validate(&trace.opts.target);
1469 if (err) {
1470 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
1471 fprintf(trace.output, "%s", bf);
1472 goto out_close;
32caf0d1
NK
1473 }
1474
514f1c67
ACM
1475 err = perf_target__parse_uid(&trace.opts.target);
1476 if (err) {
514f1c67 1477 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
1478 fprintf(trace.output, "%s", bf);
1479 goto out_close;
514f1c67
ACM
1480 }
1481
f15eb531 1482 if (!argc && perf_target__none(&trace.opts.target))
ee76120e
NK
1483 trace.opts.target.system_wide = true;
1484
6810fc91
DA
1485 if (input_name)
1486 err = trace__replay(&trace);
1487 else
1488 err = trace__run(&trace, argc, argv);
1302d88e
ACM
1489
1490 if (trace.sched && !err)
c24ff998 1491 trace__fprintf_thread_summary(&trace, trace.output);
1302d88e 1492
c24ff998
ACM
1493out_close:
1494 if (output_name != NULL)
1495 fclose(trace.output);
1496out:
1302d88e 1497 return err;
514f1c67 1498}
This page took 0.217097 seconds and 5 git commands to generate.