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