1 #include <traceevent/event-parse.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"
16 #include <sys/eventfd.h>
18 #include <linux/futex.h>
20 /* For older distros: */
22 # define MAP_STACK 0x20000
26 # define MADV_HWPOISON 100
29 #ifndef MADV_MERGEABLE
30 # define MADV_MERGEABLE 12
33 #ifndef MADV_UNMERGEABLE
34 # define MADV_UNMERGEABLE 13
39 struct thread *thread;
52 #define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
53 .nr_entries = ARRAY_SIZE(array), \
57 #define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
59 .nr_entries = ARRAY_SIZE(array), \
63 static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
65 struct syscall_arg *arg)
67 struct strarray *sa = arg->parm;
68 int idx = arg->val - sa->offset;
70 if (idx < 0 || idx >= sa->nr_entries)
71 return scnprintf(bf, size, intfmt, arg->val);
73 return scnprintf(bf, size, "%s", sa->entries[idx]);
76 static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
77 struct syscall_arg *arg)
79 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
82 #define SCA_STRARRAY syscall_arg__scnprintf_strarray
84 static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
85 struct syscall_arg *arg)
87 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
90 #define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
92 static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
93 struct syscall_arg *arg);
95 #define SCA_FD syscall_arg__scnprintf_fd
97 static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
98 struct syscall_arg *arg)
103 return scnprintf(bf, size, "CWD");
105 return syscall_arg__scnprintf_fd(bf, size, arg);
108 #define SCA_FDAT syscall_arg__scnprintf_fd_at
110 static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
111 struct syscall_arg *arg);
113 #define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
115 static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
116 struct syscall_arg *arg)
118 return scnprintf(bf, size, "%#lx", arg->val);
121 #define SCA_HEX syscall_arg__scnprintf_hex
123 static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
124 struct syscall_arg *arg)
126 int printed = 0, prot = arg->val;
128 if (prot == PROT_NONE)
129 return scnprintf(bf, size, "NONE");
130 #define P_MMAP_PROT(n) \
131 if (prot & PROT_##n) { \
132 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
142 P_MMAP_PROT(GROWSDOWN);
143 P_MMAP_PROT(GROWSUP);
147 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
152 #define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
154 static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
155 struct syscall_arg *arg)
157 int printed = 0, flags = arg->val;
159 #define P_MMAP_FLAG(n) \
160 if (flags & MAP_##n) { \
161 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
166 P_MMAP_FLAG(PRIVATE);
170 P_MMAP_FLAG(ANONYMOUS);
171 P_MMAP_FLAG(DENYWRITE);
172 P_MMAP_FLAG(EXECUTABLE);
175 P_MMAP_FLAG(GROWSDOWN);
177 P_MMAP_FLAG(HUGETLB);
180 P_MMAP_FLAG(NONBLOCK);
181 P_MMAP_FLAG(NORESERVE);
182 P_MMAP_FLAG(POPULATE);
184 #ifdef MAP_UNINITIALIZED
185 P_MMAP_FLAG(UNINITIALIZED);
190 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
195 #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
197 static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
198 struct syscall_arg *arg)
200 int behavior = arg->val;
203 #define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
206 P_MADV_BHV(SEQUENTIAL);
207 P_MADV_BHV(WILLNEED);
208 P_MADV_BHV(DONTNEED);
210 P_MADV_BHV(DONTFORK);
212 P_MADV_BHV(HWPOISON);
213 #ifdef MADV_SOFT_OFFLINE
214 P_MADV_BHV(SOFT_OFFLINE);
216 P_MADV_BHV(MERGEABLE);
217 P_MADV_BHV(UNMERGEABLE);
219 P_MADV_BHV(HUGEPAGE);
221 #ifdef MADV_NOHUGEPAGE
222 P_MADV_BHV(NOHUGEPAGE);
225 P_MADV_BHV(DONTDUMP);
234 return scnprintf(bf, size, "%#x", behavior);
237 #define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
239 static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
240 struct syscall_arg *arg)
242 int printed = 0, op = arg->val;
245 return scnprintf(bf, size, "NONE");
247 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
248 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
263 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
268 #define SCA_FLOCK syscall_arg__scnprintf_flock
270 static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
272 enum syscall_futex_args {
273 SCF_UADDR = (1 << 0),
276 SCF_TIMEOUT = (1 << 3),
277 SCF_UADDR2 = (1 << 4),
281 int cmd = op & FUTEX_CMD_MASK;
285 #define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
286 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
287 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
288 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
289 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
290 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
291 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
292 P_FUTEX_OP(WAKE_OP); break;
293 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
294 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
295 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
296 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
297 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
298 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
299 default: printed = scnprintf(bf, size, "%#x", cmd); break;
302 if (op & FUTEX_PRIVATE_FLAG)
303 printed += scnprintf(bf + printed, size - printed, "|PRIV");
305 if (op & FUTEX_CLOCK_REALTIME)
306 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
311 #define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
313 static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
314 static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
316 static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
317 static DEFINE_STRARRAY(itimers);
319 static const char *whences[] = { "SET", "CUR", "END",
327 static DEFINE_STRARRAY(whences);
329 static const char *fcntl_cmds[] = {
330 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
331 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
332 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
335 static DEFINE_STRARRAY(fcntl_cmds);
337 static const char *rlimit_resources[] = {
338 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
339 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
342 static DEFINE_STRARRAY(rlimit_resources);
344 static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
345 static DEFINE_STRARRAY(sighow);
347 static const char *clockid[] = {
348 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
349 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
351 static DEFINE_STRARRAY(clockid);
353 static const char *socket_families[] = {
354 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
355 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
356 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
357 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
358 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
359 "ALG", "NFC", "VSOCK",
361 static DEFINE_STRARRAY(socket_families);
363 #ifndef SOCK_TYPE_MASK
364 #define SOCK_TYPE_MASK 0xf
367 static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
368 struct syscall_arg *arg)
372 flags = type & ~SOCK_TYPE_MASK;
374 type &= SOCK_TYPE_MASK;
376 * Can't use a strarray, MIPS may override for ABI reasons.
379 #define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
384 P_SK_TYPE(SEQPACKET);
389 printed = scnprintf(bf, size, "%#x", type);
392 #define P_SK_FLAG(n) \
393 if (flags & SOCK_##n) { \
394 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
395 flags &= ~SOCK_##n; \
403 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
408 #define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
411 #define MSG_PROBE 0x10
413 #ifndef MSG_WAITFORONE
414 #define MSG_WAITFORONE 0x10000
416 #ifndef MSG_SENDPAGE_NOTLAST
417 #define MSG_SENDPAGE_NOTLAST 0x20000
420 #define MSG_FASTOPEN 0x20000000
423 static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
424 struct syscall_arg *arg)
426 int printed = 0, flags = arg->val;
429 return scnprintf(bf, size, "NONE");
430 #define P_MSG_FLAG(n) \
431 if (flags & MSG_##n) { \
432 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
438 P_MSG_FLAG(DONTROUTE);
443 P_MSG_FLAG(DONTWAIT);
450 P_MSG_FLAG(ERRQUEUE);
451 P_MSG_FLAG(NOSIGNAL);
453 P_MSG_FLAG(WAITFORONE);
454 P_MSG_FLAG(SENDPAGE_NOTLAST);
455 P_MSG_FLAG(FASTOPEN);
456 P_MSG_FLAG(CMSG_CLOEXEC);
460 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
465 #define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
467 static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
468 struct syscall_arg *arg)
473 if (mode == F_OK) /* 0 */
474 return scnprintf(bf, size, "F");
476 if (mode & n##_OK) { \
477 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
487 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
492 #define SCA_ACCMODE syscall_arg__scnprintf_access_mode
494 static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
495 struct syscall_arg *arg)
497 int printed = 0, flags = arg->val;
499 if (!(flags & O_CREAT))
500 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
503 return scnprintf(bf, size, "RDONLY");
505 if (flags & O_##n) { \
506 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
530 if ((flags & O_SYNC) == O_SYNC)
531 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
543 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
548 #define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
550 static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
551 struct syscall_arg *arg)
553 int printed = 0, flags = arg->val;
556 return scnprintf(bf, size, "NONE");
558 if (flags & EFD_##n) { \
559 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
569 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
574 #define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
576 static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
577 struct syscall_arg *arg)
579 int printed = 0, flags = arg->val;
582 if (flags & O_##n) { \
583 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
592 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
597 #define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
599 static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
604 #define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
639 return scnprintf(bf, size, "%#x", sig);
642 #define SCA_SIGNUM syscall_arg__scnprintf_signum
644 #define TCGETS 0x5401
646 static const char *tioctls[] = {
647 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
648 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
649 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
650 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
651 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
652 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
653 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
654 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
655 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
656 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
657 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
658 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
659 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
660 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
661 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
664 static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
666 #define STRARRAY(arg, name, array) \
667 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
668 .arg_parm = { [arg] = &strarray__##array, }
670 static struct syscall_fmt {
673 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
679 { .name = "access", .errmsg = true,
680 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
681 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
682 { .name = "brk", .hexret = true,
683 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
684 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
685 { .name = "close", .errmsg = true,
686 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
687 { .name = "connect", .errmsg = true, },
688 { .name = "dup", .errmsg = true,
689 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
690 { .name = "dup2", .errmsg = true,
691 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
692 { .name = "dup3", .errmsg = true,
693 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
694 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
695 { .name = "eventfd2", .errmsg = true,
696 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
697 { .name = "faccessat", .errmsg = true,
698 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
699 { .name = "fadvise64", .errmsg = true,
700 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
701 { .name = "fallocate", .errmsg = true,
702 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
703 { .name = "fchdir", .errmsg = true,
704 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
705 { .name = "fchmod", .errmsg = true,
706 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
707 { .name = "fchmodat", .errmsg = true,
708 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
709 { .name = "fchown", .errmsg = true,
710 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
711 { .name = "fchownat", .errmsg = true,
712 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
713 { .name = "fcntl", .errmsg = true,
714 .arg_scnprintf = { [0] = SCA_FD, /* fd */
715 [1] = SCA_STRARRAY, /* cmd */ },
716 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
717 { .name = "fdatasync", .errmsg = true,
718 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
719 { .name = "flock", .errmsg = true,
720 .arg_scnprintf = { [0] = SCA_FD, /* fd */
721 [1] = SCA_FLOCK, /* cmd */ }, },
722 { .name = "fsetxattr", .errmsg = true,
723 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
724 { .name = "fstat", .errmsg = true, .alias = "newfstat",
725 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
726 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
727 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
728 { .name = "fstatfs", .errmsg = true,
729 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
730 { .name = "fsync", .errmsg = true,
731 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
732 { .name = "ftruncate", .errmsg = true,
733 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
734 { .name = "futex", .errmsg = true,
735 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
736 { .name = "futimesat", .errmsg = true,
737 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
738 { .name = "getdents", .errmsg = true,
739 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
740 { .name = "getdents64", .errmsg = true,
741 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
742 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
743 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
744 { .name = "ioctl", .errmsg = true,
745 .arg_scnprintf = { [0] = SCA_FD, /* fd */
746 [1] = SCA_STRHEXARRAY, /* cmd */
747 [2] = SCA_HEX, /* arg */ },
748 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
749 { .name = "kill", .errmsg = true,
750 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
751 { .name = "linkat", .errmsg = true,
752 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
753 { .name = "lseek", .errmsg = true,
754 .arg_scnprintf = { [0] = SCA_FD, /* fd */
755 [2] = SCA_STRARRAY, /* whence */ },
756 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
757 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
758 { .name = "madvise", .errmsg = true,
759 .arg_scnprintf = { [0] = SCA_HEX, /* start */
760 [2] = SCA_MADV_BHV, /* behavior */ }, },
761 { .name = "mkdirat", .errmsg = true,
762 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
763 { .name = "mknodat", .errmsg = true,
764 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
765 { .name = "mlock", .errmsg = true,
766 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
767 { .name = "mlockall", .errmsg = true,
768 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
769 { .name = "mmap", .hexret = true,
770 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
771 [2] = SCA_MMAP_PROT, /* prot */
772 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
773 { .name = "mprotect", .errmsg = true,
774 .arg_scnprintf = { [0] = SCA_HEX, /* start */
775 [2] = SCA_MMAP_PROT, /* prot */ }, },
776 { .name = "mremap", .hexret = true,
777 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
778 [4] = SCA_HEX, /* new_addr */ }, },
779 { .name = "munlock", .errmsg = true,
780 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
781 { .name = "munmap", .errmsg = true,
782 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
783 { .name = "name_to_handle_at", .errmsg = true,
784 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
785 { .name = "newfstatat", .errmsg = true,
786 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
787 { .name = "open", .errmsg = true,
788 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
789 { .name = "open_by_handle_at", .errmsg = true,
790 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
791 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
792 { .name = "openat", .errmsg = true,
793 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
794 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
795 { .name = "pipe2", .errmsg = true,
796 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
797 { .name = "poll", .errmsg = true, .timeout = true, },
798 { .name = "ppoll", .errmsg = true, .timeout = true, },
799 { .name = "pread", .errmsg = true, .alias = "pread64",
800 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
801 { .name = "preadv", .errmsg = true, .alias = "pread",
802 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
803 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
804 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
805 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
806 { .name = "pwritev", .errmsg = true,
807 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
808 { .name = "read", .errmsg = true,
809 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
810 { .name = "readlinkat", .errmsg = true,
811 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
812 { .name = "readv", .errmsg = true,
813 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
814 { .name = "recvfrom", .errmsg = true,
815 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
816 { .name = "recvmmsg", .errmsg = true,
817 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
818 { .name = "recvmsg", .errmsg = true,
819 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
820 { .name = "renameat", .errmsg = true,
821 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
822 { .name = "rt_sigaction", .errmsg = true,
823 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
824 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
825 { .name = "rt_sigqueueinfo", .errmsg = true,
826 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
827 { .name = "rt_tgsigqueueinfo", .errmsg = true,
828 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
829 { .name = "select", .errmsg = true, .timeout = true, },
830 { .name = "sendmmsg", .errmsg = true,
831 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
832 { .name = "sendmsg", .errmsg = true,
833 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
834 { .name = "sendto", .errmsg = true,
835 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
836 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
837 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
838 { .name = "shutdown", .errmsg = true,
839 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
840 { .name = "socket", .errmsg = true,
841 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
842 [1] = SCA_SK_TYPE, /* type */ },
843 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
844 { .name = "socketpair", .errmsg = true,
845 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
846 [1] = SCA_SK_TYPE, /* type */ },
847 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
848 { .name = "stat", .errmsg = true, .alias = "newstat", },
849 { .name = "symlinkat", .errmsg = true,
850 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
851 { .name = "tgkill", .errmsg = true,
852 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
853 { .name = "tkill", .errmsg = true,
854 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
855 { .name = "uname", .errmsg = true, .alias = "newuname", },
856 { .name = "unlinkat", .errmsg = true,
857 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
858 { .name = "utimensat", .errmsg = true,
859 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
860 { .name = "write", .errmsg = true,
861 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
862 { .name = "writev", .errmsg = true,
863 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
866 static int syscall_fmt__cmp(const void *name, const void *fmtp)
868 const struct syscall_fmt *fmt = fmtp;
869 return strcmp(name, fmt->name);
872 static struct syscall_fmt *syscall_fmt__find(const char *name)
874 const int nmemb = ARRAY_SIZE(syscall_fmts);
875 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
879 struct event_format *tp_format;
882 struct syscall_fmt *fmt;
883 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
887 static size_t fprintf_duration(unsigned long t, FILE *fp)
889 double duration = (double)t / NSEC_PER_MSEC;
890 size_t printed = fprintf(fp, "(");
893 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
894 else if (duration >= 0.01)
895 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
897 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
898 return printed + fprintf(fp, "): ");
901 struct thread_trace {
905 unsigned long nr_events;
914 static struct thread_trace *thread_trace__new(void)
916 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
919 ttrace->paths.max = -1;
924 static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
926 struct thread_trace *ttrace;
931 if (thread->priv == NULL)
932 thread->priv = thread_trace__new();
934 if (thread->priv == NULL)
937 ttrace = thread->priv;
942 color_fprintf(fp, PERF_COLOR_RED,
943 "WARNING: not enough memory, dropping samples!\n");
948 struct perf_tool tool;
952 struct syscall *table;
954 struct perf_record_opts opts;
955 struct machine *host;
959 unsigned long nr_events;
960 struct strlist *ev_qualifier;
961 bool not_ev_qualifier;
963 struct intlist *tid_list;
964 struct intlist *pid_list;
966 bool multiple_threads;
968 double duration_filter;
972 static int thread__read_fd_path(struct thread *thread, int fd)
974 struct thread_trace *ttrace = thread->priv;
975 char linkname[PATH_MAX], pathname[PATH_MAX];
979 if (thread->pid_ == thread->tid) {
980 scnprintf(linkname, sizeof(linkname),
981 "/proc/%d/fd/%d", thread->pid_, fd);
983 scnprintf(linkname, sizeof(linkname),
984 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
987 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
990 ret = readlink(linkname, pathname, sizeof(pathname));
992 if (ret < 0 || ret > st.st_size)
995 pathname[ret] = '\0';
997 if (fd > ttrace->paths.max) {
998 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1003 if (ttrace->paths.max != -1) {
1004 memset(npath + ttrace->paths.max + 1, 0,
1005 (fd - ttrace->paths.max) * sizeof(char *));
1007 memset(npath, 0, (fd + 1) * sizeof(char *));
1010 ttrace->paths.table = npath;
1011 ttrace->paths.max = fd;
1014 ttrace->paths.table[fd] = strdup(pathname);
1016 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1019 static const char *thread__fd_path(struct thread *thread, int fd, bool live)
1021 struct thread_trace *ttrace = thread->priv;
1029 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL) &&
1030 (!live || thread__read_fd_path(thread, fd)))
1033 return ttrace->paths.table[fd];
1036 static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1037 struct syscall_arg *arg)
1040 size_t printed = scnprintf(bf, size, "%d", fd);
1041 const char *path = thread__fd_path(arg->thread, fd, arg->trace->live);
1044 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1049 static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1050 struct syscall_arg *arg)
1053 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1054 struct thread_trace *ttrace = arg->thread->priv;
1056 if (ttrace && fd >= 0 && fd <= ttrace->paths.max) {
1057 free(ttrace->paths.table[fd]);
1058 ttrace->paths.table[fd] = NULL;
1064 static bool trace__filter_duration(struct trace *trace, double t)
1066 return t < (trace->duration_filter * NSEC_PER_MSEC);
1069 static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1071 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1073 return fprintf(fp, "%10.3f ", ts);
1076 static bool done = false;
1078 static void sig_handler(int sig __maybe_unused)
1083 static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
1084 u64 duration, u64 tstamp, FILE *fp)
1086 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
1087 printed += fprintf_duration(duration, fp);
1089 if (trace->multiple_threads) {
1090 if (trace->show_comm)
1091 printed += fprintf(fp, "%.14s/", thread->comm);
1092 printed += fprintf(fp, "%d ", thread->tid);
1098 static int trace__process_event(struct trace *trace, struct machine *machine,
1099 union perf_event *event)
1103 switch (event->header.type) {
1104 case PERF_RECORD_LOST:
1105 color_fprintf(trace->output, PERF_COLOR_RED,
1106 "LOST %" PRIu64 " events!\n", event->lost.lost);
1107 ret = machine__process_lost_event(machine, event);
1109 ret = machine__process_event(machine, event);
1116 static int trace__tool_process(struct perf_tool *tool,
1117 union perf_event *event,
1118 struct perf_sample *sample __maybe_unused,
1119 struct machine *machine)
1121 struct trace *trace = container_of(tool, struct trace, tool);
1122 return trace__process_event(trace, machine, event);
1125 static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1127 int err = symbol__init();
1132 trace->host = machine__new_host();
1133 if (trace->host == NULL)
1136 if (perf_target__has_task(&trace->opts.target)) {
1137 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
1138 trace__tool_process,
1141 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
1151 static int syscall__set_arg_fmts(struct syscall *sc)
1153 struct format_field *field;
1156 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1157 if (sc->arg_scnprintf == NULL)
1161 sc->arg_parm = sc->fmt->arg_parm;
1163 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
1164 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1165 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1166 else if (field->flags & FIELD_IS_POINTER)
1167 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1174 static int trace__read_syscall_info(struct trace *trace, int id)
1178 const char *name = audit_syscall_to_name(id, trace->audit_machine);
1183 if (id > trace->syscalls.max) {
1184 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1186 if (nsyscalls == NULL)
1189 if (trace->syscalls.max != -1) {
1190 memset(nsyscalls + trace->syscalls.max + 1, 0,
1191 (id - trace->syscalls.max) * sizeof(*sc));
1193 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1196 trace->syscalls.table = nsyscalls;
1197 trace->syscalls.max = id;
1200 sc = trace->syscalls.table + id;
1203 if (trace->ev_qualifier) {
1204 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1206 if (!(in ^ trace->not_ev_qualifier)) {
1207 sc->filtered = true;
1209 * No need to do read tracepoint information since this will be
1216 sc->fmt = syscall_fmt__find(sc->name);
1218 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
1219 sc->tp_format = event_format__new("syscalls", tp_name);
1221 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1222 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
1223 sc->tp_format = event_format__new("syscalls", tp_name);
1226 if (sc->tp_format == NULL)
1229 return syscall__set_arg_fmts(sc);
1232 static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
1233 unsigned long *args, struct trace *trace,
1234 struct thread *thread)
1238 if (sc->tp_format != NULL) {
1239 struct format_field *field;
1241 struct syscall_arg arg = {
1248 for (field = sc->tp_format->format.fields->next; field;
1249 field = field->next, ++arg.idx, bit <<= 1) {
1253 * Suppress this argument if its value is zero and
1254 * and we don't have a string associated in an
1257 if (args[arg.idx] == 0 &&
1258 !(sc->arg_scnprintf &&
1259 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1260 sc->arg_parm[arg.idx]))
1263 printed += scnprintf(bf + printed, size - printed,
1264 "%s%s: ", printed ? ", " : "", field->name);
1265 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1266 arg.val = args[arg.idx];
1268 arg.parm = sc->arg_parm[arg.idx];
1269 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1270 size - printed, &arg);
1272 printed += scnprintf(bf + printed, size - printed,
1273 "%ld", args[arg.idx]);
1280 printed += scnprintf(bf + printed, size - printed,
1282 printed ? ", " : "", i, args[i]);
1290 typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1291 struct perf_sample *sample);
1293 static struct syscall *trace__syscall_info(struct trace *trace,
1294 struct perf_evsel *evsel,
1295 struct perf_sample *sample)
1297 int id = perf_evsel__intval(evsel, sample, "id");
1302 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1303 * before that, leaving at a higher verbosity level till that is
1304 * explained. Reproduced with plain ftrace with:
1306 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1307 * grep "NR -1 " /t/trace_pipe
1309 * After generating some load on the machine.
1313 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1314 id, perf_evsel__name(evsel), ++n);
1319 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1320 trace__read_syscall_info(trace, id))
1323 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1326 return &trace->syscalls.table[id];
1330 fprintf(trace->output, "Problems reading syscall %d", id);
1331 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1332 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1333 fputs(" information\n", trace->output);
1338 static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1339 struct perf_sample *sample)
1344 struct thread *thread;
1345 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
1346 struct thread_trace *ttrace;
1354 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1355 ttrace = thread__trace(thread, trace->output);
1359 args = perf_evsel__rawptr(evsel, sample, "args");
1361 fprintf(trace->output, "Problems reading syscall arguments\n");
1365 ttrace = thread->priv;
1367 if (ttrace->entry_str == NULL) {
1368 ttrace->entry_str = malloc(1024);
1369 if (!ttrace->entry_str)
1373 ttrace->entry_time = sample->time;
1374 msg = ttrace->entry_str;
1375 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1377 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1378 args, trace, thread);
1380 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
1381 if (!trace->duration_filter) {
1382 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1383 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
1386 ttrace->entry_pending = true;
1391 static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1392 struct perf_sample *sample)
1396 struct thread *thread;
1397 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
1398 struct thread_trace *ttrace;
1406 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1407 ttrace = thread__trace(thread, trace->output);
1411 ret = perf_evsel__intval(evsel, sample, "ret");
1413 ttrace = thread->priv;
1415 ttrace->exit_time = sample->time;
1417 if (ttrace->entry_time) {
1418 duration = sample->time - ttrace->entry_time;
1419 if (trace__filter_duration(trace, duration))
1421 } else if (trace->duration_filter)
1424 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
1426 if (ttrace->entry_pending) {
1427 fprintf(trace->output, "%-70s", ttrace->entry_str);
1429 fprintf(trace->output, " ... [");
1430 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1431 fprintf(trace->output, "]: %s()", sc->name);
1434 if (sc->fmt == NULL) {
1436 fprintf(trace->output, ") = %d", ret);
1437 } else if (ret < 0 && sc->fmt->errmsg) {
1439 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1440 *e = audit_errno_to_name(-ret);
1442 fprintf(trace->output, ") = -1 %s %s", e, emsg);
1443 } else if (ret == 0 && sc->fmt->timeout)
1444 fprintf(trace->output, ") = 0 Timeout");
1445 else if (sc->fmt->hexret)
1446 fprintf(trace->output, ") = %#x", ret);
1450 fputc('\n', trace->output);
1452 ttrace->entry_pending = false;
1457 static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1458 struct perf_sample *sample)
1460 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1461 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
1462 struct thread *thread = machine__findnew_thread(trace->host,
1465 struct thread_trace *ttrace = thread__trace(thread, trace->output);
1470 ttrace->runtime_ms += runtime_ms;
1471 trace->runtime_ms += runtime_ms;
1475 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
1477 perf_evsel__strval(evsel, sample, "comm"),
1478 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1480 perf_evsel__intval(evsel, sample, "vruntime"));
1484 static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1486 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1487 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1490 if (trace->pid_list || trace->tid_list)
1496 static int trace__process_sample(struct perf_tool *tool,
1497 union perf_event *event __maybe_unused,
1498 struct perf_sample *sample,
1499 struct perf_evsel *evsel,
1500 struct machine *machine __maybe_unused)
1502 struct trace *trace = container_of(tool, struct trace, tool);
1505 tracepoint_handler handler = evsel->handler.func;
1507 if (skip_sample(trace, sample))
1510 if (!trace->full_time && trace->base_time == 0)
1511 trace->base_time = sample->time;
1514 handler(trace, evsel, sample);
1520 perf_session__has_tp(struct perf_session *session, const char *name)
1522 struct perf_evsel *evsel;
1524 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1526 return evsel != NULL;
1529 static int parse_target_str(struct trace *trace)
1531 if (trace->opts.target.pid) {
1532 trace->pid_list = intlist__new(trace->opts.target.pid);
1533 if (trace->pid_list == NULL) {
1534 pr_err("Error parsing process id string\n");
1539 if (trace->opts.target.tid) {
1540 trace->tid_list = intlist__new(trace->opts.target.tid);
1541 if (trace->tid_list == NULL) {
1542 pr_err("Error parsing thread id string\n");
1550 static int trace__record(int argc, const char **argv)
1552 unsigned int rec_argc, i, j;
1553 const char **rec_argv;
1554 const char * const record_args[] = {
1559 "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit",
1562 rec_argc = ARRAY_SIZE(record_args) + argc;
1563 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1565 if (rec_argv == NULL)
1568 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1569 rec_argv[i] = record_args[i];
1571 for (j = 0; j < (unsigned int)argc; j++, i++)
1572 rec_argv[i] = argv[j];
1574 return cmd_record(i, rec_argv, NULL);
1577 static int trace__run(struct trace *trace, int argc, const char **argv)
1579 struct perf_evlist *evlist = perf_evlist__new();
1580 struct perf_evsel *evsel;
1582 unsigned long before;
1583 const bool forks = argc > 0;
1587 if (evlist == NULL) {
1588 fprintf(trace->output, "Not enough memory to run!\n");
1592 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1593 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
1594 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
1595 goto out_delete_evlist;
1599 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1600 trace__sched_stat_runtime)) {
1601 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
1602 goto out_delete_evlist;
1605 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1607 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
1608 goto out_delete_evlist;
1611 err = trace__symbols_init(trace, evlist);
1613 fprintf(trace->output, "Problems initializing symbol libraries!\n");
1614 goto out_delete_maps;
1617 perf_evlist__config(evlist, &trace->opts);
1619 signal(SIGCHLD, sig_handler);
1620 signal(SIGINT, sig_handler);
1623 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
1624 argv, false, false);
1626 fprintf(trace->output, "Couldn't run the workload!\n");
1627 goto out_delete_maps;
1631 err = perf_evlist__open(evlist);
1633 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
1634 goto out_delete_maps;
1637 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1639 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
1640 goto out_close_evlist;
1643 perf_evlist__enable(evlist);
1646 perf_evlist__start_workload(evlist);
1648 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
1650 before = trace->nr_events;
1652 for (i = 0; i < evlist->nr_mmaps; i++) {
1653 union perf_event *event;
1655 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1656 const u32 type = event->header.type;
1657 tracepoint_handler handler;
1658 struct perf_sample sample;
1662 err = perf_evlist__parse_sample(evlist, event, &sample);
1664 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
1668 if (!trace->full_time && trace->base_time == 0)
1669 trace->base_time = sample.time;
1671 if (type != PERF_RECORD_SAMPLE) {
1672 trace__process_event(trace, trace->host, event);
1676 evsel = perf_evlist__id2evsel(evlist, sample.id);
1677 if (evsel == NULL) {
1678 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
1682 if (sample.raw_data == NULL) {
1683 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
1684 perf_evsel__name(evsel), sample.tid,
1685 sample.cpu, sample.raw_size);
1689 handler = evsel->handler.func;
1690 handler(trace, evsel, &sample);
1693 goto out_unmap_evlist;
1697 if (trace->nr_events == before) {
1699 goto out_unmap_evlist;
1701 poll(evlist->pollfd, evlist->nr_fds, -1);
1705 perf_evlist__disable(evlist);
1710 perf_evlist__munmap(evlist);
1712 perf_evlist__close(evlist);
1714 perf_evlist__delete_maps(evlist);
1716 perf_evlist__delete(evlist);
1718 trace->live = false;
1722 static int trace__replay(struct trace *trace)
1724 const struct perf_evsel_str_handler handlers[] = {
1725 { "raw_syscalls:sys_enter", trace__sys_enter, },
1726 { "raw_syscalls:sys_exit", trace__sys_exit, },
1729 struct perf_session *session;
1732 trace->tool.sample = trace__process_sample;
1733 trace->tool.mmap = perf_event__process_mmap;
1734 trace->tool.mmap2 = perf_event__process_mmap2;
1735 trace->tool.comm = perf_event__process_comm;
1736 trace->tool.exit = perf_event__process_exit;
1737 trace->tool.fork = perf_event__process_fork;
1738 trace->tool.attr = perf_event__process_attr;
1739 trace->tool.tracing_data = perf_event__process_tracing_data;
1740 trace->tool.build_id = perf_event__process_build_id;
1742 trace->tool.ordered_samples = true;
1743 trace->tool.ordering_requires_timestamps = true;
1745 /* add tid to output */
1746 trace->multiple_threads = true;
1748 if (symbol__init() < 0)
1751 session = perf_session__new(input_name, O_RDONLY, 0, false,
1753 if (session == NULL)
1756 trace->host = &session->machines.host;
1758 err = perf_session__set_tracepoints_handlers(session, handlers);
1762 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1763 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1767 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1768 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1772 err = parse_target_str(trace);
1778 err = perf_session__process_events(session, &trace->tool);
1780 pr_err("Failed to process events, error %d", err);
1783 perf_session__delete(session);
1788 static size_t trace__fprintf_threads_header(FILE *fp)
1792 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1793 printed += fprintf(fp," __) Summary of events (__\n\n");
1794 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1795 printed += fprintf(fp," _____________________________________________________________________\n\n");
1800 /* struct used to pass data to per-thread function */
1801 struct summary_data {
1803 struct trace *trace;
1807 static int trace__fprintf_one_thread(struct thread *thread, void *priv)
1809 struct summary_data *data = priv;
1810 FILE *fp = data->fp;
1811 size_t printed = data->printed;
1812 struct trace *trace = data->trace;
1813 struct thread_trace *ttrace = thread->priv;
1820 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1822 color = PERF_COLOR_NORMAL;
1824 color = PERF_COLOR_RED;
1825 else if (ratio > 25.0)
1826 color = PERF_COLOR_GREEN;
1827 else if (ratio > 5.0)
1828 color = PERF_COLOR_YELLOW;
1830 printed += color_fprintf(fp, color, "%20s", thread->comm);
1831 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
1832 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1833 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1835 data->printed += printed;
1840 static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1842 struct summary_data data = {
1846 data.printed = trace__fprintf_threads_header(fp);
1848 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
1850 return data.printed;
1853 static int trace__set_duration(const struct option *opt, const char *str,
1854 int unset __maybe_unused)
1856 struct trace *trace = opt->value;
1858 trace->duration_filter = atof(str);
1862 static int trace__open_output(struct trace *trace, const char *filename)
1866 if (!stat(filename, &st) && st.st_size) {
1867 char oldname[PATH_MAX];
1869 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1871 rename(filename, oldname);
1874 trace->output = fopen(filename, "w");
1876 return trace->output == NULL ? -errno : 0;
1879 int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1881 const char * const trace_usage[] = {
1882 "perf trace [<options>] [<command>]",
1883 "perf trace [<options>] -- <command> [<options>]",
1884 "perf trace record [<options>] [<command>]",
1885 "perf trace record [<options>] -- <command> [<options>]",
1888 struct trace trace = {
1889 .audit_machine = audit_detect_machine(),
1898 .user_freq = UINT_MAX,
1899 .user_interval = ULLONG_MAX,
1906 const char *output_name = NULL;
1907 const char *ev_qualifier_str = NULL;
1908 const struct option trace_options[] = {
1909 OPT_BOOLEAN(0, "comm", &trace.show_comm,
1910 "show the thread COMM next to its id"),
1911 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1912 "list of events to trace"),
1913 OPT_STRING('o', "output", &output_name, "file", "output file name"),
1914 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
1915 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1916 "trace events on existing process id"),
1917 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
1918 "trace events on existing thread id"),
1919 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
1920 "system-wide collection from all CPUs"),
1921 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
1922 "list of cpus to monitor"),
1923 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
1924 "child tasks do not inherit counters"),
1925 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
1926 "number of mmap data pages",
1927 perf_evlist__parse_mmap_pages),
1928 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
1930 OPT_CALLBACK(0, "duration", &trace, "float",
1931 "show only events with duration > N.M ms",
1932 trace__set_duration),
1933 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
1934 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
1935 OPT_BOOLEAN('T', "time", &trace.full_time,
1936 "Show full timestamp, not time relative to first start"),
1942 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
1943 return trace__record(argc-2, &argv[2]);
1945 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
1947 if (output_name != NULL) {
1948 err = trace__open_output(&trace, output_name);
1950 perror("failed to create output file");
1955 if (ev_qualifier_str != NULL) {
1956 const char *s = ev_qualifier_str;
1958 trace.not_ev_qualifier = *s == '!';
1959 if (trace.not_ev_qualifier)
1961 trace.ev_qualifier = strlist__new(true, s);
1962 if (trace.ev_qualifier == NULL) {
1963 fputs("Not enough memory to parse event qualifier",
1970 err = perf_target__validate(&trace.opts.target);
1972 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
1973 fprintf(trace.output, "%s", bf);
1977 err = perf_target__parse_uid(&trace.opts.target);
1979 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
1980 fprintf(trace.output, "%s", bf);
1984 if (!argc && perf_target__none(&trace.opts.target))
1985 trace.opts.target.system_wide = true;
1988 err = trace__replay(&trace);
1990 err = trace__run(&trace, argc, argv);
1992 if (trace.sched && !err)
1993 trace__fprintf_thread_summary(&trace, trace.output);
1996 if (output_name != NULL)
1997 fclose(trace.output);