aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-trace.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-trace.c')
-rw-r--r--tools/perf/builtin-trace.c1403
1 files changed, 1225 insertions, 178 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 99c8d9ad6729..329b7832b5da 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -10,9 +10,11 @@
10#include "util/strlist.h" 10#include "util/strlist.h"
11#include "util/intlist.h" 11#include "util/intlist.h"
12#include "util/thread_map.h" 12#include "util/thread_map.h"
13#include "util/stat.h"
13 14
14#include <libaudit.h> 15#include <libaudit.h>
15#include <stdlib.h> 16#include <stdlib.h>
17#include <sys/eventfd.h>
16#include <sys/mman.h> 18#include <sys/mman.h>
17#include <linux/futex.h> 19#include <linux/futex.h>
18 20
@@ -33,49 +35,279 @@
33# define MADV_UNMERGEABLE 13 35# define MADV_UNMERGEABLE 13
34#endif 36#endif
35 37
36static size_t syscall_arg__scnprintf_hex(char *bf, size_t size, 38struct tp_field {
37 unsigned long arg, 39 int offset;
38 u8 arg_idx __maybe_unused, 40 union {
39 u8 *arg_mask __maybe_unused) 41 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
42 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
43 };
44};
45
46#define TP_UINT_FIELD(bits) \
47static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
48{ \
49 return *(u##bits *)(sample->raw_data + field->offset); \
50}
51
52TP_UINT_FIELD(8);
53TP_UINT_FIELD(16);
54TP_UINT_FIELD(32);
55TP_UINT_FIELD(64);
56
57#define TP_UINT_FIELD__SWAPPED(bits) \
58static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
59{ \
60 u##bits value = *(u##bits *)(sample->raw_data + field->offset); \
61 return bswap_##bits(value);\
62}
63
64TP_UINT_FIELD__SWAPPED(16);
65TP_UINT_FIELD__SWAPPED(32);
66TP_UINT_FIELD__SWAPPED(64);
67
68static int tp_field__init_uint(struct tp_field *field,
69 struct format_field *format_field,
70 bool needs_swap)
40{ 71{
41 return scnprintf(bf, size, "%#lx", arg); 72 field->offset = format_field->offset;
73
74 switch (format_field->size) {
75 case 1:
76 field->integer = tp_field__u8;
77 break;
78 case 2:
79 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
80 break;
81 case 4:
82 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
83 break;
84 case 8:
85 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
86 break;
87 default:
88 return -1;
89 }
90
91 return 0;
42} 92}
43 93
44#define SCA_HEX syscall_arg__scnprintf_hex 94static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
95{
96 return sample->raw_data + field->offset;
97}
45 98
46static size_t syscall_arg__scnprintf_whence(char *bf, size_t size, 99static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
47 unsigned long arg,
48 u8 arg_idx __maybe_unused,
49 u8 *arg_mask __maybe_unused)
50{ 100{
51 int whence = arg; 101 field->offset = format_field->offset;
102 field->pointer = tp_field__ptr;
103 return 0;
104}
52 105
53 switch (whence) { 106struct syscall_tp {
54#define P_WHENCE(n) case SEEK_##n: return scnprintf(bf, size, #n) 107 struct tp_field id;
55 P_WHENCE(SET); 108 union {
56 P_WHENCE(CUR); 109 struct tp_field args, ret;
57 P_WHENCE(END); 110 };
58#ifdef SEEK_DATA 111};
59 P_WHENCE(DATA); 112
60#endif 113static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
61#ifdef SEEK_HOLE 114 struct tp_field *field,
62 P_WHENCE(HOLE); 115 const char *name)
63#endif 116{
64#undef P_WHENCE 117 struct format_field *format_field = perf_evsel__field(evsel, name);
65 default: break; 118
119 if (format_field == NULL)
120 return -1;
121
122 return tp_field__init_uint(field, format_field, evsel->needs_swap);
123}
124
125#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
126 ({ struct syscall_tp *sc = evsel->priv;\
127 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
128
129static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
130 struct tp_field *field,
131 const char *name)
132{
133 struct format_field *format_field = perf_evsel__field(evsel, name);
134
135 if (format_field == NULL)
136 return -1;
137
138 return tp_field__init_ptr(field, format_field);
139}
140
141#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
142 ({ struct syscall_tp *sc = evsel->priv;\
143 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
144
145static void perf_evsel__delete_priv(struct perf_evsel *evsel)
146{
147 free(evsel->priv);
148 evsel->priv = NULL;
149 perf_evsel__delete(evsel);
150}
151
152static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction,
153 void *handler, int idx)
154{
155 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction, idx);
156
157 if (evsel) {
158 evsel->priv = malloc(sizeof(struct syscall_tp));
159
160 if (evsel->priv == NULL)
161 goto out_delete;
162
163 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
164 goto out_delete;
165
166 evsel->handler = handler;
66 } 167 }
67 168
68 return scnprintf(bf, size, "%#x", whence); 169 return evsel;
170
171out_delete:
172 perf_evsel__delete_priv(evsel);
173 return NULL;
69} 174}
70 175
71#define SCA_WHENCE syscall_arg__scnprintf_whence 176#define perf_evsel__sc_tp_uint(evsel, name, sample) \
177 ({ struct syscall_tp *fields = evsel->priv; \
178 fields->name.integer(&fields->name, sample); })
179
180#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
181 ({ struct syscall_tp *fields = evsel->priv; \
182 fields->name.pointer(&fields->name, sample); })
183
184static int perf_evlist__add_syscall_newtp(struct perf_evlist *evlist,
185 void *sys_enter_handler,
186 void *sys_exit_handler)
187{
188 int ret = -1;
189 int idx = evlist->nr_entries;
190 struct perf_evsel *sys_enter, *sys_exit;
191
192 sys_enter = perf_evsel__syscall_newtp("sys_enter", sys_enter_handler, idx++);
193 if (sys_enter == NULL)
194 goto out;
195
196 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
197 goto out_delete_sys_enter;
198
199 sys_exit = perf_evsel__syscall_newtp("sys_exit", sys_exit_handler, idx++);
200 if (sys_exit == NULL)
201 goto out_delete_sys_enter;
202
203 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
204 goto out_delete_sys_exit;
205
206 perf_evlist__add(evlist, sys_enter);
207 perf_evlist__add(evlist, sys_exit);
208
209 ret = 0;
210out:
211 return ret;
212
213out_delete_sys_exit:
214 perf_evsel__delete_priv(sys_exit);
215out_delete_sys_enter:
216 perf_evsel__delete_priv(sys_enter);
217 goto out;
218}
219
220
221struct syscall_arg {
222 unsigned long val;
223 struct thread *thread;
224 struct trace *trace;
225 void *parm;
226 u8 idx;
227 u8 mask;
228};
229
230struct strarray {
231 int offset;
232 int nr_entries;
233 const char **entries;
234};
235
236#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
237 .nr_entries = ARRAY_SIZE(array), \
238 .entries = array, \
239}
240
241#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
242 .offset = off, \
243 .nr_entries = ARRAY_SIZE(array), \
244 .entries = array, \
245}
246
247static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
248 const char *intfmt,
249 struct syscall_arg *arg)
250{
251 struct strarray *sa = arg->parm;
252 int idx = arg->val - sa->offset;
253
254 if (idx < 0 || idx >= sa->nr_entries)
255 return scnprintf(bf, size, intfmt, arg->val);
256
257 return scnprintf(bf, size, "%s", sa->entries[idx]);
258}
259
260static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
261 struct syscall_arg *arg)
262{
263 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
264}
265
266#define SCA_STRARRAY syscall_arg__scnprintf_strarray
267
268static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
269 struct syscall_arg *arg)
270{
271 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
272}
273
274#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
275
276static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
277 struct syscall_arg *arg);
278
279#define SCA_FD syscall_arg__scnprintf_fd
280
281static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
282 struct syscall_arg *arg)
283{
284 int fd = arg->val;
285
286 if (fd == AT_FDCWD)
287 return scnprintf(bf, size, "CWD");
288
289 return syscall_arg__scnprintf_fd(bf, size, arg);
290}
291
292#define SCA_FDAT syscall_arg__scnprintf_fd_at
293
294static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
295 struct syscall_arg *arg);
296
297#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
298
299static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
300 struct syscall_arg *arg)
301{
302 return scnprintf(bf, size, "%#lx", arg->val);
303}
304
305#define SCA_HEX syscall_arg__scnprintf_hex
72 306
73static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, 307static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
74 unsigned long arg, 308 struct syscall_arg *arg)
75 u8 arg_idx __maybe_unused,
76 u8 *arg_mask __maybe_unused)
77{ 309{
78 int printed = 0, prot = arg; 310 int printed = 0, prot = arg->val;
79 311
80 if (prot == PROT_NONE) 312 if (prot == PROT_NONE)
81 return scnprintf(bf, size, "NONE"); 313 return scnprintf(bf, size, "NONE");
@@ -104,10 +336,9 @@ static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
104#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot 336#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
105 337
106static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, 338static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
107 unsigned long arg, u8 arg_idx __maybe_unused, 339 struct syscall_arg *arg)
108 u8 *arg_mask __maybe_unused)
109{ 340{
110 int printed = 0, flags = arg; 341 int printed = 0, flags = arg->val;
111 342
112#define P_MMAP_FLAG(n) \ 343#define P_MMAP_FLAG(n) \
113 if (flags & MAP_##n) { \ 344 if (flags & MAP_##n) { \
@@ -148,10 +379,9 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
148#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags 379#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
149 380
150static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, 381static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
151 unsigned long arg, u8 arg_idx __maybe_unused, 382 struct syscall_arg *arg)
152 u8 *arg_mask __maybe_unused)
153{ 383{
154 int behavior = arg; 384 int behavior = arg->val;
155 385
156 switch (behavior) { 386 switch (behavior) {
157#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n) 387#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
@@ -190,8 +420,38 @@ static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
190 420
191#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior 421#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
192 422
193static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, unsigned long arg, 423static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
194 u8 arg_idx __maybe_unused, u8 *arg_mask) 424 struct syscall_arg *arg)
425{
426 int printed = 0, op = arg->val;
427
428 if (op == 0)
429 return scnprintf(bf, size, "NONE");
430#define P_CMD(cmd) \
431 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
432 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
433 op &= ~LOCK_##cmd; \
434 }
435
436 P_CMD(SH);
437 P_CMD(EX);
438 P_CMD(NB);
439 P_CMD(UN);
440 P_CMD(MAND);
441 P_CMD(RW);
442 P_CMD(READ);
443 P_CMD(WRITE);
444#undef P_OP
445
446 if (op)
447 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
448
449 return printed;
450}
451
452#define SCA_FLOCK syscall_arg__scnprintf_flock
453
454static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
195{ 455{
196 enum syscall_futex_args { 456 enum syscall_futex_args {
197 SCF_UADDR = (1 << 0), 457 SCF_UADDR = (1 << 0),
@@ -201,24 +461,24 @@ static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, unsigned lo
201 SCF_UADDR2 = (1 << 4), 461 SCF_UADDR2 = (1 << 4),
202 SCF_VAL3 = (1 << 5), 462 SCF_VAL3 = (1 << 5),
203 }; 463 };
204 int op = arg; 464 int op = arg->val;
205 int cmd = op & FUTEX_CMD_MASK; 465 int cmd = op & FUTEX_CMD_MASK;
206 size_t printed = 0; 466 size_t printed = 0;
207 467
208 switch (cmd) { 468 switch (cmd) {
209#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n); 469#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
210 P_FUTEX_OP(WAIT); *arg_mask |= SCF_VAL3|SCF_UADDR2; break; 470 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
211 P_FUTEX_OP(WAKE); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; 471 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
212 P_FUTEX_OP(FD); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; 472 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
213 P_FUTEX_OP(REQUEUE); *arg_mask |= SCF_VAL3|SCF_TIMEOUT; break; 473 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
214 P_FUTEX_OP(CMP_REQUEUE); *arg_mask |= SCF_TIMEOUT; break; 474 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
215 P_FUTEX_OP(CMP_REQUEUE_PI); *arg_mask |= SCF_TIMEOUT; break; 475 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
216 P_FUTEX_OP(WAKE_OP); break; 476 P_FUTEX_OP(WAKE_OP); break;
217 P_FUTEX_OP(LOCK_PI); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; 477 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
218 P_FUTEX_OP(UNLOCK_PI); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; 478 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
219 P_FUTEX_OP(TRYLOCK_PI); *arg_mask |= SCF_VAL3|SCF_UADDR2; break; 479 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
220 P_FUTEX_OP(WAIT_BITSET); *arg_mask |= SCF_UADDR2; break; 480 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
221 P_FUTEX_OP(WAKE_BITSET); *arg_mask |= SCF_UADDR2; break; 481 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
222 P_FUTEX_OP(WAIT_REQUEUE_PI); break; 482 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
223 default: printed = scnprintf(bf, size, "%#x", cmd); break; 483 default: printed = scnprintf(bf, size, "%#x", cmd); break;
224 } 484 }
@@ -234,14 +494,194 @@ static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, unsigned lo
234 494
235#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op 495#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
236 496
497static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
498static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
499
500static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
501static DEFINE_STRARRAY(itimers);
502
503static const char *whences[] = { "SET", "CUR", "END",
504#ifdef SEEK_DATA
505"DATA",
506#endif
507#ifdef SEEK_HOLE
508"HOLE",
509#endif
510};
511static DEFINE_STRARRAY(whences);
512
513static const char *fcntl_cmds[] = {
514 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
515 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
516 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
517 "F_GETOWNER_UIDS",
518};
519static DEFINE_STRARRAY(fcntl_cmds);
520
521static const char *rlimit_resources[] = {
522 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
523 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
524 "RTTIME",
525};
526static DEFINE_STRARRAY(rlimit_resources);
527
528static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
529static DEFINE_STRARRAY(sighow);
530
531static const char *clockid[] = {
532 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
533 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
534};
535static DEFINE_STRARRAY(clockid);
536
537static const char *socket_families[] = {
538 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
539 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
540 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
541 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
542 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
543 "ALG", "NFC", "VSOCK",
544};
545static DEFINE_STRARRAY(socket_families);
546
547#ifndef SOCK_TYPE_MASK
548#define SOCK_TYPE_MASK 0xf
549#endif
550
551static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
552 struct syscall_arg *arg)
553{
554 size_t printed;
555 int type = arg->val,
556 flags = type & ~SOCK_TYPE_MASK;
557
558 type &= SOCK_TYPE_MASK;
559 /*
560 * Can't use a strarray, MIPS may override for ABI reasons.
561 */
562 switch (type) {
563#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
564 P_SK_TYPE(STREAM);
565 P_SK_TYPE(DGRAM);
566 P_SK_TYPE(RAW);
567 P_SK_TYPE(RDM);
568 P_SK_TYPE(SEQPACKET);
569 P_SK_TYPE(DCCP);
570 P_SK_TYPE(PACKET);
571#undef P_SK_TYPE
572 default:
573 printed = scnprintf(bf, size, "%#x", type);
574 }
575
576#define P_SK_FLAG(n) \
577 if (flags & SOCK_##n) { \
578 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
579 flags &= ~SOCK_##n; \
580 }
581
582 P_SK_FLAG(CLOEXEC);
583 P_SK_FLAG(NONBLOCK);
584#undef P_SK_FLAG
585
586 if (flags)
587 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
588
589 return printed;
590}
591
592#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
593
594#ifndef MSG_PROBE
595#define MSG_PROBE 0x10
596#endif
597#ifndef MSG_WAITFORONE
598#define MSG_WAITFORONE 0x10000
599#endif
600#ifndef MSG_SENDPAGE_NOTLAST
601#define MSG_SENDPAGE_NOTLAST 0x20000
602#endif
603#ifndef MSG_FASTOPEN
604#define MSG_FASTOPEN 0x20000000
605#endif
606
607static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
608 struct syscall_arg *arg)
609{
610 int printed = 0, flags = arg->val;
611
612 if (flags == 0)
613 return scnprintf(bf, size, "NONE");
614#define P_MSG_FLAG(n) \
615 if (flags & MSG_##n) { \
616 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
617 flags &= ~MSG_##n; \
618 }
619
620 P_MSG_FLAG(OOB);
621 P_MSG_FLAG(PEEK);
622 P_MSG_FLAG(DONTROUTE);
623 P_MSG_FLAG(TRYHARD);
624 P_MSG_FLAG(CTRUNC);
625 P_MSG_FLAG(PROBE);
626 P_MSG_FLAG(TRUNC);
627 P_MSG_FLAG(DONTWAIT);
628 P_MSG_FLAG(EOR);
629 P_MSG_FLAG(WAITALL);
630 P_MSG_FLAG(FIN);
631 P_MSG_FLAG(SYN);
632 P_MSG_FLAG(CONFIRM);
633 P_MSG_FLAG(RST);
634 P_MSG_FLAG(ERRQUEUE);
635 P_MSG_FLAG(NOSIGNAL);
636 P_MSG_FLAG(MORE);
637 P_MSG_FLAG(WAITFORONE);
638 P_MSG_FLAG(SENDPAGE_NOTLAST);
639 P_MSG_FLAG(FASTOPEN);
640 P_MSG_FLAG(CMSG_CLOEXEC);
641#undef P_MSG_FLAG
642
643 if (flags)
644 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
645
646 return printed;
647}
648
649#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
650
651static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
652 struct syscall_arg *arg)
653{
654 size_t printed = 0;
655 int mode = arg->val;
656
657 if (mode == F_OK) /* 0 */
658 return scnprintf(bf, size, "F");
659#define P_MODE(n) \
660 if (mode & n##_OK) { \
661 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
662 mode &= ~n##_OK; \
663 }
664
665 P_MODE(R);
666 P_MODE(W);
667 P_MODE(X);
668#undef P_MODE
669
670 if (mode)
671 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
672
673 return printed;
674}
675
676#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
677
237static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size, 678static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
238 unsigned long arg, 679 struct syscall_arg *arg)
239 u8 arg_idx, u8 *arg_mask)
240{ 680{
241 int printed = 0, flags = arg; 681 int printed = 0, flags = arg->val;
242 682
243 if (!(flags & O_CREAT)) 683 if (!(flags & O_CREAT))
244 *arg_mask |= 1 << (arg_idx + 1); /* Mask the mode parm */ 684 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
245 685
246 if (flags == 0) 686 if (flags == 0)
247 return scnprintf(bf, size, "RDONLY"); 687 return scnprintf(bf, size, "RDONLY");
@@ -291,32 +731,225 @@ static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
291 731
292#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags 732#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
293 733
734static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
735 struct syscall_arg *arg)
736{
737 int printed = 0, flags = arg->val;
738
739 if (flags == 0)
740 return scnprintf(bf, size, "NONE");
741#define P_FLAG(n) \
742 if (flags & EFD_##n) { \
743 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
744 flags &= ~EFD_##n; \
745 }
746
747 P_FLAG(SEMAPHORE);
748 P_FLAG(CLOEXEC);
749 P_FLAG(NONBLOCK);
750#undef P_FLAG
751
752 if (flags)
753 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
754
755 return printed;
756}
757
758#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
759
760static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
761 struct syscall_arg *arg)
762{
763 int printed = 0, flags = arg->val;
764
765#define P_FLAG(n) \
766 if (flags & O_##n) { \
767 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
768 flags &= ~O_##n; \
769 }
770
771 P_FLAG(CLOEXEC);
772 P_FLAG(NONBLOCK);
773#undef P_FLAG
774
775 if (flags)
776 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
777
778 return printed;
779}
780
781#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
782
783static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
784{
785 int sig = arg->val;
786
787 switch (sig) {
788#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
789 P_SIGNUM(HUP);
790 P_SIGNUM(INT);
791 P_SIGNUM(QUIT);
792 P_SIGNUM(ILL);
793 P_SIGNUM(TRAP);
794 P_SIGNUM(ABRT);
795 P_SIGNUM(BUS);
796 P_SIGNUM(FPE);
797 P_SIGNUM(KILL);
798 P_SIGNUM(USR1);
799 P_SIGNUM(SEGV);
800 P_SIGNUM(USR2);
801 P_SIGNUM(PIPE);
802 P_SIGNUM(ALRM);
803 P_SIGNUM(TERM);
804 P_SIGNUM(STKFLT);
805 P_SIGNUM(CHLD);
806 P_SIGNUM(CONT);
807 P_SIGNUM(STOP);
808 P_SIGNUM(TSTP);
809 P_SIGNUM(TTIN);
810 P_SIGNUM(TTOU);
811 P_SIGNUM(URG);
812 P_SIGNUM(XCPU);
813 P_SIGNUM(XFSZ);
814 P_SIGNUM(VTALRM);
815 P_SIGNUM(PROF);
816 P_SIGNUM(WINCH);
817 P_SIGNUM(IO);
818 P_SIGNUM(PWR);
819 P_SIGNUM(SYS);
820 default: break;
821 }
822
823 return scnprintf(bf, size, "%#x", sig);
824}
825
826#define SCA_SIGNUM syscall_arg__scnprintf_signum
827
828#define TCGETS 0x5401
829
830static const char *tioctls[] = {
831 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
832 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
833 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
834 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
835 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
836 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
837 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
838 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
839 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
840 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
841 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
842 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
843 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
844 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
845 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
846};
847
848static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
849
850#define STRARRAY(arg, name, array) \
851 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
852 .arg_parm = { [arg] = &strarray__##array, }
853
294static struct syscall_fmt { 854static struct syscall_fmt {
295 const char *name; 855 const char *name;
296 const char *alias; 856 const char *alias;
297 size_t (*arg_scnprintf[6])(char *bf, size_t size, unsigned long arg, u8 arg_idx, u8 *arg_mask); 857 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
858 void *arg_parm[6];
298 bool errmsg; 859 bool errmsg;
299 bool timeout; 860 bool timeout;
300 bool hexret; 861 bool hexret;
301} syscall_fmts[] = { 862} syscall_fmts[] = {
302 { .name = "access", .errmsg = true, }, 863 { .name = "access", .errmsg = true,
864 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
303 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", }, 865 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
304 { .name = "brk", .hexret = true, 866 { .name = "brk", .hexret = true,
305 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, }, 867 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
306 { .name = "mmap", .hexret = true, }, 868 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
869 { .name = "close", .errmsg = true,
870 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
307 { .name = "connect", .errmsg = true, }, 871 { .name = "connect", .errmsg = true, },
308 { .name = "fstat", .errmsg = true, .alias = "newfstat", }, 872 { .name = "dup", .errmsg = true,
309 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", }, 873 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
874 { .name = "dup2", .errmsg = true,
875 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
876 { .name = "dup3", .errmsg = true,
877 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
878 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
879 { .name = "eventfd2", .errmsg = true,
880 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
881 { .name = "faccessat", .errmsg = true,
882 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
883 { .name = "fadvise64", .errmsg = true,
884 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
885 { .name = "fallocate", .errmsg = true,
886 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
887 { .name = "fchdir", .errmsg = true,
888 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
889 { .name = "fchmod", .errmsg = true,
890 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
891 { .name = "fchmodat", .errmsg = true,
892 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
893 { .name = "fchown", .errmsg = true,
894 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
895 { .name = "fchownat", .errmsg = true,
896 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
897 { .name = "fcntl", .errmsg = true,
898 .arg_scnprintf = { [0] = SCA_FD, /* fd */
899 [1] = SCA_STRARRAY, /* cmd */ },
900 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
901 { .name = "fdatasync", .errmsg = true,
902 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
903 { .name = "flock", .errmsg = true,
904 .arg_scnprintf = { [0] = SCA_FD, /* fd */
905 [1] = SCA_FLOCK, /* cmd */ }, },
906 { .name = "fsetxattr", .errmsg = true,
907 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
908 { .name = "fstat", .errmsg = true, .alias = "newfstat",
909 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
910 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
911 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
912 { .name = "fstatfs", .errmsg = true,
913 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
914 { .name = "fsync", .errmsg = true,
915 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
916 { .name = "ftruncate", .errmsg = true,
917 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
310 { .name = "futex", .errmsg = true, 918 { .name = "futex", .errmsg = true,
311 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, }, 919 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
920 { .name = "futimesat", .errmsg = true,
921 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
922 { .name = "getdents", .errmsg = true,
923 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
924 { .name = "getdents64", .errmsg = true,
925 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
926 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
927 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
312 { .name = "ioctl", .errmsg = true, 928 { .name = "ioctl", .errmsg = true,
313 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, }, 929 .arg_scnprintf = { [0] = SCA_FD, /* fd */
930 [1] = SCA_STRHEXARRAY, /* cmd */
931 [2] = SCA_HEX, /* arg */ },
932 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
933 { .name = "kill", .errmsg = true,
934 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
935 { .name = "linkat", .errmsg = true,
936 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
314 { .name = "lseek", .errmsg = true, 937 { .name = "lseek", .errmsg = true,
315 .arg_scnprintf = { [2] = SCA_WHENCE, /* whence */ }, }, 938 .arg_scnprintf = { [0] = SCA_FD, /* fd */
939 [2] = SCA_STRARRAY, /* whence */ },
940 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
316 { .name = "lstat", .errmsg = true, .alias = "newlstat", }, 941 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
317 { .name = "madvise", .errmsg = true, 942 { .name = "madvise", .errmsg = true,
318 .arg_scnprintf = { [0] = SCA_HEX, /* start */ 943 .arg_scnprintf = { [0] = SCA_HEX, /* start */
319 [2] = SCA_MADV_BHV, /* behavior */ }, }, 944 [2] = SCA_MADV_BHV, /* behavior */ }, },
945 { .name = "mkdirat", .errmsg = true,
946 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
947 { .name = "mknodat", .errmsg = true,
948 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
949 { .name = "mlock", .errmsg = true,
950 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
951 { .name = "mlockall", .errmsg = true,
952 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
320 { .name = "mmap", .hexret = true, 953 { .name = "mmap", .hexret = true,
321 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ 954 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
322 [2] = SCA_MMAP_PROT, /* prot */ 955 [2] = SCA_MMAP_PROT, /* prot */
@@ -327,24 +960,91 @@ static struct syscall_fmt {
327 { .name = "mremap", .hexret = true, 960 { .name = "mremap", .hexret = true,
328 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ 961 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
329 [4] = SCA_HEX, /* new_addr */ }, }, 962 [4] = SCA_HEX, /* new_addr */ }, },
963 { .name = "munlock", .errmsg = true,
964 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
330 { .name = "munmap", .errmsg = true, 965 { .name = "munmap", .errmsg = true,
331 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, 966 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
967 { .name = "name_to_handle_at", .errmsg = true,
968 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
969 { .name = "newfstatat", .errmsg = true,
970 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
332 { .name = "open", .errmsg = true, 971 { .name = "open", .errmsg = true,
333 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, }, 972 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
334 { .name = "open_by_handle_at", .errmsg = true, 973 { .name = "open_by_handle_at", .errmsg = true,
335 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, }, 974 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
975 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
336 { .name = "openat", .errmsg = true, 976 { .name = "openat", .errmsg = true,
337 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, }, 977 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
978 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
979 { .name = "pipe2", .errmsg = true,
980 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
338 { .name = "poll", .errmsg = true, .timeout = true, }, 981 { .name = "poll", .errmsg = true, .timeout = true, },
339 { .name = "ppoll", .errmsg = true, .timeout = true, }, 982 { .name = "ppoll", .errmsg = true, .timeout = true, },
340 { .name = "pread", .errmsg = true, .alias = "pread64", }, 983 { .name = "pread", .errmsg = true, .alias = "pread64",
341 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", }, 984 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
342 { .name = "read", .errmsg = true, }, 985 { .name = "preadv", .errmsg = true, .alias = "pread",
343 { .name = "recvfrom", .errmsg = true, }, 986 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
987 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
988 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
989 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
990 { .name = "pwritev", .errmsg = true,
991 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
992 { .name = "read", .errmsg = true,
993 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
994 { .name = "readlinkat", .errmsg = true,
995 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
996 { .name = "readv", .errmsg = true,
997 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
998 { .name = "recvfrom", .errmsg = true,
999 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1000 { .name = "recvmmsg", .errmsg = true,
1001 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1002 { .name = "recvmsg", .errmsg = true,
1003 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
1004 { .name = "renameat", .errmsg = true,
1005 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1006 { .name = "rt_sigaction", .errmsg = true,
1007 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
1008 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
1009 { .name = "rt_sigqueueinfo", .errmsg = true,
1010 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1011 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1012 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
344 { .name = "select", .errmsg = true, .timeout = true, }, 1013 { .name = "select", .errmsg = true, .timeout = true, },
345 { .name = "socket", .errmsg = true, }, 1014 { .name = "sendmmsg", .errmsg = true,
1015 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1016 { .name = "sendmsg", .errmsg = true,
1017 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
1018 { .name = "sendto", .errmsg = true,
1019 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1020 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1021 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
1022 { .name = "shutdown", .errmsg = true,
1023 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1024 { .name = "socket", .errmsg = true,
1025 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1026 [1] = SCA_SK_TYPE, /* type */ },
1027 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
1028 { .name = "socketpair", .errmsg = true,
1029 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1030 [1] = SCA_SK_TYPE, /* type */ },
1031 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
346 { .name = "stat", .errmsg = true, .alias = "newstat", }, 1032 { .name = "stat", .errmsg = true, .alias = "newstat", },
1033 { .name = "symlinkat", .errmsg = true,
1034 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1035 { .name = "tgkill", .errmsg = true,
1036 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1037 { .name = "tkill", .errmsg = true,
1038 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
347 { .name = "uname", .errmsg = true, .alias = "newuname", }, 1039 { .name = "uname", .errmsg = true, .alias = "newuname", },
1040 { .name = "unlinkat", .errmsg = true,
1041 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1042 { .name = "utimensat", .errmsg = true,
1043 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
1044 { .name = "write", .errmsg = true,
1045 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1046 { .name = "writev", .errmsg = true,
1047 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
348}; 1048};
349 1049
350static int syscall_fmt__cmp(const void *name, const void *fmtp) 1050static int syscall_fmt__cmp(const void *name, const void *fmtp)
@@ -364,8 +1064,8 @@ struct syscall {
364 const char *name; 1064 const char *name;
365 bool filtered; 1065 bool filtered;
366 struct syscall_fmt *fmt; 1066 struct syscall_fmt *fmt;
367 size_t (**arg_scnprintf)(char *bf, size_t size, 1067 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
368 unsigned long arg, u8 arg_idx, u8 *args_mask); 1068 void **arg_parm;
369}; 1069};
370 1070
371static size_t fprintf_duration(unsigned long t, FILE *fp) 1071static size_t fprintf_duration(unsigned long t, FILE *fp)
@@ -389,11 +1089,24 @@ struct thread_trace {
389 unsigned long nr_events; 1089 unsigned long nr_events;
390 char *entry_str; 1090 char *entry_str;
391 double runtime_ms; 1091 double runtime_ms;
1092 struct {
1093 int max;
1094 char **table;
1095 } paths;
1096
1097 struct intlist *syscall_stats;
392}; 1098};
393 1099
394static struct thread_trace *thread_trace__new(void) 1100static struct thread_trace *thread_trace__new(void)
395{ 1101{
396 return zalloc(sizeof(struct thread_trace)); 1102 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1103
1104 if (ttrace)
1105 ttrace->paths.max = -1;
1106
1107 ttrace->syscall_stats = intlist__new(NULL);
1108
1109 return ttrace;
397} 1110}
398 1111
399static struct thread_trace *thread__trace(struct thread *thread, FILE *fp) 1112static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
@@ -421,26 +1134,140 @@ fail:
421 1134
422struct trace { 1135struct trace {
423 struct perf_tool tool; 1136 struct perf_tool tool;
424 int audit_machine; 1137 struct {
1138 int machine;
1139 int open_id;
1140 } audit;
425 struct { 1141 struct {
426 int max; 1142 int max;
427 struct syscall *table; 1143 struct syscall *table;
428 } syscalls; 1144 } syscalls;
429 struct perf_record_opts opts; 1145 struct perf_record_opts opts;
430 struct machine host; 1146 struct machine *host;
431 u64 base_time; 1147 u64 base_time;
1148 bool full_time;
432 FILE *output; 1149 FILE *output;
433 unsigned long nr_events; 1150 unsigned long nr_events;
434 struct strlist *ev_qualifier; 1151 struct strlist *ev_qualifier;
435 bool not_ev_qualifier; 1152 bool not_ev_qualifier;
1153 bool live;
1154 const char *last_vfs_getname;
436 struct intlist *tid_list; 1155 struct intlist *tid_list;
437 struct intlist *pid_list; 1156 struct intlist *pid_list;
438 bool sched; 1157 bool sched;
439 bool multiple_threads; 1158 bool multiple_threads;
1159 bool summary;
1160 bool show_comm;
1161 bool show_tool_stats;
440 double duration_filter; 1162 double duration_filter;
441 double runtime_ms; 1163 double runtime_ms;
1164 struct {
1165 u64 vfs_getname, proc_getname;
1166 } stats;
442}; 1167};
443 1168
1169static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
1170{
1171 struct thread_trace *ttrace = thread->priv;
1172
1173 if (fd > ttrace->paths.max) {
1174 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1175
1176 if (npath == NULL)
1177 return -1;
1178
1179 if (ttrace->paths.max != -1) {
1180 memset(npath + ttrace->paths.max + 1, 0,
1181 (fd - ttrace->paths.max) * sizeof(char *));
1182 } else {
1183 memset(npath, 0, (fd + 1) * sizeof(char *));
1184 }
1185
1186 ttrace->paths.table = npath;
1187 ttrace->paths.max = fd;
1188 }
1189
1190 ttrace->paths.table[fd] = strdup(pathname);
1191
1192 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1193}
1194
1195static int thread__read_fd_path(struct thread *thread, int fd)
1196{
1197 char linkname[PATH_MAX], pathname[PATH_MAX];
1198 struct stat st;
1199 int ret;
1200
1201 if (thread->pid_ == thread->tid) {
1202 scnprintf(linkname, sizeof(linkname),
1203 "/proc/%d/fd/%d", thread->pid_, fd);
1204 } else {
1205 scnprintf(linkname, sizeof(linkname),
1206 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1207 }
1208
1209 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1210 return -1;
1211
1212 ret = readlink(linkname, pathname, sizeof(pathname));
1213
1214 if (ret < 0 || ret > st.st_size)
1215 return -1;
1216
1217 pathname[ret] = '\0';
1218 return trace__set_fd_pathname(thread, fd, pathname);
1219}
1220
1221static const char *thread__fd_path(struct thread *thread, int fd,
1222 struct trace *trace)
1223{
1224 struct thread_trace *ttrace = thread->priv;
1225
1226 if (ttrace == NULL)
1227 return NULL;
1228
1229 if (fd < 0)
1230 return NULL;
1231
1232 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL))
1233 if (!trace->live)
1234 return NULL;
1235 ++trace->stats.proc_getname;
1236 if (thread__read_fd_path(thread, fd)) {
1237 return NULL;
1238 }
1239
1240 return ttrace->paths.table[fd];
1241}
1242
1243static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1244 struct syscall_arg *arg)
1245{
1246 int fd = arg->val;
1247 size_t printed = scnprintf(bf, size, "%d", fd);
1248 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
1249
1250 if (path)
1251 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1252
1253 return printed;
1254}
1255
1256static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1257 struct syscall_arg *arg)
1258{
1259 int fd = arg->val;
1260 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1261 struct thread_trace *ttrace = arg->thread->priv;
1262
1263 if (ttrace && fd >= 0 && fd <= ttrace->paths.max) {
1264 free(ttrace->paths.table[fd]);
1265 ttrace->paths.table[fd] = NULL;
1266 }
1267
1268 return printed;
1269}
1270
444static bool trace__filter_duration(struct trace *trace, double t) 1271static bool trace__filter_duration(struct trace *trace, double t)
445{ 1272{
446 return t < (trace->duration_filter * NSEC_PER_MSEC); 1273 return t < (trace->duration_filter * NSEC_PER_MSEC);
@@ -454,10 +1281,12 @@ static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
454} 1281}
455 1282
456static bool done = false; 1283static bool done = false;
1284static bool interrupted = false;
457 1285
458static void sig_handler(int sig __maybe_unused) 1286static void sig_handler(int sig)
459{ 1287{
460 done = true; 1288 done = true;
1289 interrupted = sig == SIGINT;
461} 1290}
462 1291
463static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread, 1292static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
@@ -466,14 +1295,17 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre
466 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp); 1295 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
467 printed += fprintf_duration(duration, fp); 1296 printed += fprintf_duration(duration, fp);
468 1297
469 if (trace->multiple_threads) 1298 if (trace->multiple_threads) {
1299 if (trace->show_comm)
1300 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
470 printed += fprintf(fp, "%d ", thread->tid); 1301 printed += fprintf(fp, "%d ", thread->tid);
1302 }
471 1303
472 return printed; 1304 return printed;
473} 1305}
474 1306
475static int trace__process_event(struct trace *trace, struct machine *machine, 1307static int trace__process_event(struct trace *trace, struct machine *machine,
476 union perf_event *event) 1308 union perf_event *event, struct perf_sample *sample)
477{ 1309{
478 int ret = 0; 1310 int ret = 0;
479 1311
@@ -481,9 +1313,9 @@ static int trace__process_event(struct trace *trace, struct machine *machine,
481 case PERF_RECORD_LOST: 1313 case PERF_RECORD_LOST:
482 color_fprintf(trace->output, PERF_COLOR_RED, 1314 color_fprintf(trace->output, PERF_COLOR_RED,
483 "LOST %" PRIu64 " events!\n", event->lost.lost); 1315 "LOST %" PRIu64 " events!\n", event->lost.lost);
484 ret = machine__process_lost_event(machine, event); 1316 ret = machine__process_lost_event(machine, event, sample);
485 default: 1317 default:
486 ret = machine__process_event(machine, event); 1318 ret = machine__process_event(machine, event, sample);
487 break; 1319 break;
488 } 1320 }
489 1321
@@ -492,11 +1324,11 @@ static int trace__process_event(struct trace *trace, struct machine *machine,
492 1324
493static int trace__tool_process(struct perf_tool *tool, 1325static int trace__tool_process(struct perf_tool *tool,
494 union perf_event *event, 1326 union perf_event *event,
495 struct perf_sample *sample __maybe_unused, 1327 struct perf_sample *sample,
496 struct machine *machine) 1328 struct machine *machine)
497{ 1329{
498 struct trace *trace = container_of(tool, struct trace, tool); 1330 struct trace *trace = container_of(tool, struct trace, tool);
499 return trace__process_event(trace, machine, event); 1331 return trace__process_event(trace, machine, event, sample);
500} 1332}
501 1333
502static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) 1334static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
@@ -506,16 +1338,17 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
506 if (err) 1338 if (err)
507 return err; 1339 return err;
508 1340
509 machine__init(&trace->host, "", HOST_KERNEL_ID); 1341 trace->host = machine__new_host();
510 machine__create_kernel_maps(&trace->host); 1342 if (trace->host == NULL)
1343 return -ENOMEM;
511 1344
512 if (perf_target__has_task(&trace->opts.target)) { 1345 if (perf_target__has_task(&trace->opts.target)) {
513 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads, 1346 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
514 trace__tool_process, 1347 trace__tool_process,
515 &trace->host); 1348 trace->host);
516 } else { 1349 } else {
517 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process, 1350 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
518 &trace->host); 1351 trace->host);
519 } 1352 }
520 1353
521 if (err) 1354 if (err)
@@ -533,6 +1366,9 @@ static int syscall__set_arg_fmts(struct syscall *sc)
533 if (sc->arg_scnprintf == NULL) 1366 if (sc->arg_scnprintf == NULL)
534 return -1; 1367 return -1;
535 1368
1369 if (sc->fmt)
1370 sc->arg_parm = sc->fmt->arg_parm;
1371
536 for (field = sc->tp_format->format.fields->next; field; field = field->next) { 1372 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
537 if (sc->fmt && sc->fmt->arg_scnprintf[idx]) 1373 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
538 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx]; 1374 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
@@ -548,7 +1384,7 @@ static int trace__read_syscall_info(struct trace *trace, int id)
548{ 1384{
549 char tp_name[128]; 1385 char tp_name[128];
550 struct syscall *sc; 1386 struct syscall *sc;
551 const char *name = audit_syscall_to_name(id, trace->audit_machine); 1387 const char *name = audit_syscall_to_name(id, trace->audit.machine);
552 1388
553 if (name == NULL) 1389 if (name == NULL)
554 return -1; 1390 return -1;
@@ -603,32 +1439,52 @@ static int trace__read_syscall_info(struct trace *trace, int id)
603} 1439}
604 1440
605static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size, 1441static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
606 unsigned long *args) 1442 unsigned long *args, struct trace *trace,
1443 struct thread *thread)
607{ 1444{
608 int i = 0;
609 size_t printed = 0; 1445 size_t printed = 0;
610 1446
611 if (sc->tp_format != NULL) { 1447 if (sc->tp_format != NULL) {
612 struct format_field *field; 1448 struct format_field *field;
613 u8 mask = 0, bit = 1; 1449 u8 bit = 1;
1450 struct syscall_arg arg = {
1451 .idx = 0,
1452 .mask = 0,
1453 .trace = trace,
1454 .thread = thread,
1455 };
614 1456
615 for (field = sc->tp_format->format.fields->next; field; 1457 for (field = sc->tp_format->format.fields->next; field;
616 field = field->next, ++i, bit <<= 1) { 1458 field = field->next, ++arg.idx, bit <<= 1) {
617 if (mask & bit) 1459 if (arg.mask & bit)
1460 continue;
1461 /*
1462 * Suppress this argument if its value is zero and
1463 * and we don't have a string associated in an
1464 * strarray for it.
1465 */
1466 if (args[arg.idx] == 0 &&
1467 !(sc->arg_scnprintf &&
1468 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1469 sc->arg_parm[arg.idx]))
618 continue; 1470 continue;
619 1471
620 printed += scnprintf(bf + printed, size - printed, 1472 printed += scnprintf(bf + printed, size - printed,
621 "%s%s: ", printed ? ", " : "", field->name); 1473 "%s%s: ", printed ? ", " : "", field->name);
622 1474 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
623 if (sc->arg_scnprintf && sc->arg_scnprintf[i]) { 1475 arg.val = args[arg.idx];
624 printed += sc->arg_scnprintf[i](bf + printed, size - printed, 1476 if (sc->arg_parm)
625 args[i], i, &mask); 1477 arg.parm = sc->arg_parm[arg.idx];
1478 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1479 size - printed, &arg);
626 } else { 1480 } else {
627 printed += scnprintf(bf + printed, size - printed, 1481 printed += scnprintf(bf + printed, size - printed,
628 "%ld", args[i]); 1482 "%ld", args[arg.idx]);
629 } 1483 }
630 } 1484 }
631 } else { 1485 } else {
1486 int i = 0;
1487
632 while (i < 6) { 1488 while (i < 6) {
633 printed += scnprintf(bf + printed, size - printed, 1489 printed += scnprintf(bf + printed, size - printed,
634 "%sarg%d: %ld", 1490 "%sarg%d: %ld",
@@ -644,10 +1500,8 @@ typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
644 struct perf_sample *sample); 1500 struct perf_sample *sample);
645 1501
646static struct syscall *trace__syscall_info(struct trace *trace, 1502static struct syscall *trace__syscall_info(struct trace *trace,
647 struct perf_evsel *evsel, 1503 struct perf_evsel *evsel, int id)
648 struct perf_sample *sample)
649{ 1504{
650 int id = perf_evsel__intval(evsel, sample, "id");
651 1505
652 if (id < 0) { 1506 if (id < 0) {
653 1507
@@ -688,6 +1542,32 @@ out_cant_read:
688 return NULL; 1542 return NULL;
689} 1543}
690 1544
1545static void thread__update_stats(struct thread_trace *ttrace,
1546 int id, struct perf_sample *sample)
1547{
1548 struct int_node *inode;
1549 struct stats *stats;
1550 u64 duration = 0;
1551
1552 inode = intlist__findnew(ttrace->syscall_stats, id);
1553 if (inode == NULL)
1554 return;
1555
1556 stats = inode->priv;
1557 if (stats == NULL) {
1558 stats = malloc(sizeof(struct stats));
1559 if (stats == NULL)
1560 return;
1561 init_stats(stats);
1562 inode->priv = stats;
1563 }
1564
1565 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1566 duration = sample->time - ttrace->entry_time;
1567
1568 update_stats(stats, duration);
1569}
1570
691static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, 1571static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
692 struct perf_sample *sample) 1572 struct perf_sample *sample)
693{ 1573{
@@ -695,7 +1575,8 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
695 void *args; 1575 void *args;
696 size_t printed = 0; 1576 size_t printed = 0;
697 struct thread *thread; 1577 struct thread *thread;
698 struct syscall *sc = trace__syscall_info(trace, evsel, sample); 1578 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
1579 struct syscall *sc = trace__syscall_info(trace, evsel, id);
699 struct thread_trace *ttrace; 1580 struct thread_trace *ttrace;
700 1581
701 if (sc == NULL) 1582 if (sc == NULL)
@@ -704,18 +1585,12 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
704 if (sc->filtered) 1585 if (sc->filtered)
705 return 0; 1586 return 0;
706 1587
707 thread = machine__findnew_thread(&trace->host, sample->pid, 1588 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
708 sample->tid);
709 ttrace = thread__trace(thread, trace->output); 1589 ttrace = thread__trace(thread, trace->output);
710 if (ttrace == NULL) 1590 if (ttrace == NULL)
711 return -1; 1591 return -1;
712 1592
713 args = perf_evsel__rawptr(evsel, sample, "args"); 1593 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
714 if (args == NULL) {
715 fprintf(trace->output, "Problems reading syscall arguments\n");
716 return -1;
717 }
718
719 ttrace = thread->priv; 1594 ttrace = thread->priv;
720 1595
721 if (ttrace->entry_str == NULL) { 1596 if (ttrace->entry_str == NULL) {
@@ -728,7 +1603,8 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
728 msg = ttrace->entry_str; 1603 msg = ttrace->entry_str;
729 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name); 1604 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
730 1605
731 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args); 1606 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1607 args, trace, thread);
732 1608
733 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) { 1609 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
734 if (!trace->duration_filter) { 1610 if (!trace->duration_filter) {
@@ -747,7 +1623,8 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
747 int ret; 1623 int ret;
748 u64 duration = 0; 1624 u64 duration = 0;
749 struct thread *thread; 1625 struct thread *thread;
750 struct syscall *sc = trace__syscall_info(trace, evsel, sample); 1626 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
1627 struct syscall *sc = trace__syscall_info(trace, evsel, id);
751 struct thread_trace *ttrace; 1628 struct thread_trace *ttrace;
752 1629
753 if (sc == NULL) 1630 if (sc == NULL)
@@ -756,13 +1633,21 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
756 if (sc->filtered) 1633 if (sc->filtered)
757 return 0; 1634 return 0;
758 1635
759 thread = machine__findnew_thread(&trace->host, sample->pid, 1636 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
760 sample->tid);
761 ttrace = thread__trace(thread, trace->output); 1637 ttrace = thread__trace(thread, trace->output);
762 if (ttrace == NULL) 1638 if (ttrace == NULL)
763 return -1; 1639 return -1;
764 1640
765 ret = perf_evsel__intval(evsel, sample, "ret"); 1641 if (trace->summary)
1642 thread__update_stats(ttrace, id, sample);
1643
1644 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
1645
1646 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1647 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1648 trace->last_vfs_getname = NULL;
1649 ++trace->stats.vfs_getname;
1650 }
766 1651
767 ttrace = thread->priv; 1652 ttrace = thread->priv;
768 1653
@@ -808,12 +1693,19 @@ out:
808 return 0; 1693 return 0;
809} 1694}
810 1695
1696static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1697 struct perf_sample *sample)
1698{
1699 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1700 return 0;
1701}
1702
811static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel, 1703static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
812 struct perf_sample *sample) 1704 struct perf_sample *sample)
813{ 1705{
814 u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); 1706 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
815 double runtime_ms = (double)runtime / NSEC_PER_MSEC; 1707 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
816 struct thread *thread = machine__findnew_thread(&trace->host, 1708 struct thread *thread = machine__findnew_thread(trace->host,
817 sample->pid, 1709 sample->pid,
818 sample->tid); 1710 sample->tid);
819 struct thread_trace *ttrace = thread__trace(thread, trace->output); 1711 struct thread_trace *ttrace = thread__trace(thread, trace->output);
@@ -856,12 +1748,12 @@ static int trace__process_sample(struct perf_tool *tool,
856 struct trace *trace = container_of(tool, struct trace, tool); 1748 struct trace *trace = container_of(tool, struct trace, tool);
857 int err = 0; 1749 int err = 0;
858 1750
859 tracepoint_handler handler = evsel->handler.func; 1751 tracepoint_handler handler = evsel->handler;
860 1752
861 if (skip_sample(trace, sample)) 1753 if (skip_sample(trace, sample))
862 return 0; 1754 return 0;
863 1755
864 if (trace->base_time == 0) 1756 if (!trace->full_time && trace->base_time == 0)
865 trace->base_time = sample->time; 1757 trace->base_time = sample->time;
866 1758
867 if (handler) 1759 if (handler)
@@ -901,6 +1793,51 @@ static int parse_target_str(struct trace *trace)
901 return 0; 1793 return 0;
902} 1794}
903 1795
1796static int trace__record(int argc, const char **argv)
1797{
1798 unsigned int rec_argc, i, j;
1799 const char **rec_argv;
1800 const char * const record_args[] = {
1801 "record",
1802 "-R",
1803 "-m", "1024",
1804 "-c", "1",
1805 "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit",
1806 };
1807
1808 rec_argc = ARRAY_SIZE(record_args) + argc;
1809 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1810
1811 if (rec_argv == NULL)
1812 return -ENOMEM;
1813
1814 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1815 rec_argv[i] = record_args[i];
1816
1817 for (j = 0; j < (unsigned int)argc; j++, i++)
1818 rec_argv[i] = argv[j];
1819
1820 return cmd_record(i, rec_argv, NULL);
1821}
1822
1823static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
1824
1825static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
1826{
1827 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname",
1828 evlist->nr_entries);
1829 if (evsel == NULL)
1830 return;
1831
1832 if (perf_evsel__field(evsel, "pathname") == NULL) {
1833 perf_evsel__delete(evsel);
1834 return;
1835 }
1836
1837 evsel->handler = trace__vfs_getname;
1838 perf_evlist__add(evlist, evsel);
1839}
1840
904static int trace__run(struct trace *trace, int argc, const char **argv) 1841static int trace__run(struct trace *trace, int argc, const char **argv)
905{ 1842{
906 struct perf_evlist *evlist = perf_evlist__new(); 1843 struct perf_evlist *evlist = perf_evlist__new();
@@ -909,23 +1846,22 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
909 unsigned long before; 1846 unsigned long before;
910 const bool forks = argc > 0; 1847 const bool forks = argc > 0;
911 1848
1849 trace->live = true;
1850
912 if (evlist == NULL) { 1851 if (evlist == NULL) {
913 fprintf(trace->output, "Not enough memory to run!\n"); 1852 fprintf(trace->output, "Not enough memory to run!\n");
914 goto out; 1853 goto out;
915 } 1854 }
916 1855
917 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) || 1856 if (perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, trace__sys_exit))
918 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) { 1857 goto out_error_tp;
919 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n"); 1858
920 goto out_delete_evlist; 1859 perf_evlist__add_vfs_getname(evlist);
921 }
922 1860
923 if (trace->sched && 1861 if (trace->sched &&
924 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", 1862 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
925 trace__sched_stat_runtime)) { 1863 trace__sched_stat_runtime))
926 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n"); 1864 goto out_error_tp;
927 goto out_delete_evlist;
928 }
929 1865
930 err = perf_evlist__create_maps(evlist, &trace->opts.target); 1866 err = perf_evlist__create_maps(evlist, &trace->opts.target);
931 if (err < 0) { 1867 if (err < 0) {
@@ -954,10 +1890,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
954 } 1890 }
955 1891
956 err = perf_evlist__open(evlist); 1892 err = perf_evlist__open(evlist);
957 if (err < 0) { 1893 if (err < 0)
958 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno)); 1894 goto out_error_open;
959 goto out_delete_maps;
960 }
961 1895
962 err = perf_evlist__mmap(evlist, UINT_MAX, false); 1896 err = perf_evlist__mmap(evlist, UINT_MAX, false);
963 if (err < 0) { 1897 if (err < 0) {
@@ -990,11 +1924,11 @@ again:
990 goto next_event; 1924 goto next_event;
991 } 1925 }
992 1926
993 if (trace->base_time == 0) 1927 if (!trace->full_time && trace->base_time == 0)
994 trace->base_time = sample.time; 1928 trace->base_time = sample.time;
995 1929
996 if (type != PERF_RECORD_SAMPLE) { 1930 if (type != PERF_RECORD_SAMPLE) {
997 trace__process_event(trace, &trace->host, event); 1931 trace__process_event(trace, trace->host, event, &sample);
998 continue; 1932 continue;
999 } 1933 }
1000 1934
@@ -1011,29 +1945,41 @@ again:
1011 goto next_event; 1945 goto next_event;
1012 } 1946 }
1013 1947
1014 handler = evsel->handler.func; 1948 handler = evsel->handler;
1015 handler(trace, evsel, &sample); 1949 handler(trace, evsel, &sample);
1016next_event: 1950next_event:
1017 perf_evlist__mmap_consume(evlist, i); 1951 perf_evlist__mmap_consume(evlist, i);
1018 1952
1019 if (done) 1953 if (interrupted)
1020 goto out_unmap_evlist; 1954 goto out_disable;
1021 } 1955 }
1022 } 1956 }
1023 1957
1024 if (trace->nr_events == before) { 1958 if (trace->nr_events == before) {
1025 if (done) 1959 int timeout = done ? 100 : -1;
1026 goto out_unmap_evlist;
1027 1960
1028 poll(evlist->pollfd, evlist->nr_fds, -1); 1961 if (poll(evlist->pollfd, evlist->nr_fds, timeout) > 0)
1962 goto again;
1963 } else {
1964 goto again;
1029 } 1965 }
1030 1966
1031 if (done) 1967out_disable:
1032 perf_evlist__disable(evlist); 1968 perf_evlist__disable(evlist);
1033 1969
1034 goto again; 1970 if (!err) {
1971 if (trace->summary)
1972 trace__fprintf_thread_summary(trace, trace->output);
1973
1974 if (trace->show_tool_stats) {
1975 fprintf(trace->output, "Stats:\n "
1976 " vfs_getname : %" PRIu64 "\n"
1977 " proc_getname: %" PRIu64 "\n",
1978 trace->stats.vfs_getname,
1979 trace->stats.proc_getname);
1980 }
1981 }
1035 1982
1036out_unmap_evlist:
1037 perf_evlist__munmap(evlist); 1983 perf_evlist__munmap(evlist);
1038out_close_evlist: 1984out_close_evlist:
1039 perf_evlist__close(evlist); 1985 perf_evlist__close(evlist);
@@ -1042,7 +1988,22 @@ out_delete_maps:
1042out_delete_evlist: 1988out_delete_evlist:
1043 perf_evlist__delete(evlist); 1989 perf_evlist__delete(evlist);
1044out: 1990out:
1991 trace->live = false;
1045 return err; 1992 return err;
1993{
1994 char errbuf[BUFSIZ];
1995
1996out_error_tp:
1997 perf_evlist__strerror_tp(evlist, errno, errbuf, sizeof(errbuf));
1998 goto out_error;
1999
2000out_error_open:
2001 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2002
2003out_error:
2004 fprintf(trace->output, "%s\n", errbuf);
2005 goto out_delete_evlist;
2006}
1046} 2007}
1047 2008
1048static int trace__replay(struct trace *trace) 2009static int trace__replay(struct trace *trace)
@@ -1050,8 +2011,12 @@ static int trace__replay(struct trace *trace)
1050 const struct perf_evsel_str_handler handlers[] = { 2011 const struct perf_evsel_str_handler handlers[] = {
1051 { "raw_syscalls:sys_enter", trace__sys_enter, }, 2012 { "raw_syscalls:sys_enter", trace__sys_enter, },
1052 { "raw_syscalls:sys_exit", trace__sys_exit, }, 2013 { "raw_syscalls:sys_exit", trace__sys_exit, },
2014 { "probe:vfs_getname", trace__vfs_getname, },
2015 };
2016 struct perf_data_file file = {
2017 .path = input_name,
2018 .mode = PERF_DATA_MODE_READ,
1053 }; 2019 };
1054
1055 struct perf_session *session; 2020 struct perf_session *session;
1056 int err = -1; 2021 int err = -1;
1057 2022
@@ -1074,11 +2039,12 @@ static int trace__replay(struct trace *trace)
1074 if (symbol__init() < 0) 2039 if (symbol__init() < 0)
1075 return -1; 2040 return -1;
1076 2041
1077 session = perf_session__new(input_name, O_RDONLY, 0, false, 2042 session = perf_session__new(&file, false, &trace->tool);
1078 &trace->tool);
1079 if (session == NULL) 2043 if (session == NULL)
1080 return -ENOMEM; 2044 return -ENOMEM;
1081 2045
2046 trace->host = &session->machines.host;
2047
1082 err = perf_session__set_tracepoints_handlers(session, handlers); 2048 err = perf_session__set_tracepoints_handlers(session, handlers);
1083 if (err) 2049 if (err)
1084 goto out; 2050 goto out;
@@ -1103,6 +2069,9 @@ static int trace__replay(struct trace *trace)
1103 if (err) 2069 if (err)
1104 pr_err("Failed to process events, error %d", err); 2070 pr_err("Failed to process events, error %d", err);
1105 2071
2072 else if (trace->summary)
2073 trace__fprintf_thread_summary(trace, trace->output);
2074
1106out: 2075out:
1107 perf_session__delete(session); 2076 perf_session__delete(session);
1108 2077
@@ -1113,47 +2082,111 @@ static size_t trace__fprintf_threads_header(FILE *fp)
1113{ 2082{
1114 size_t printed; 2083 size_t printed;
1115 2084
1116 printed = fprintf(fp, "\n _____________________________________________________________________\n"); 2085 printed = fprintf(fp, "\n _____________________________________________________________________________\n");
1117 printed += fprintf(fp," __) Summary of events (__\n\n"); 2086 printed += fprintf(fp, " __) Summary of events (__\n\n");
1118 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n"); 2087 printed += fprintf(fp, " [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1119 printed += fprintf(fp," _____________________________________________________________________\n\n"); 2088 printed += fprintf(fp, " syscall count min max avg stddev\n");
2089 printed += fprintf(fp, " msec msec msec %%\n");
2090 printed += fprintf(fp, " _____________________________________________________________________________\n\n");
1120 2091
1121 return printed; 2092 return printed;
1122} 2093}
1123 2094
1124static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp) 2095static size_t thread__dump_stats(struct thread_trace *ttrace,
2096 struct trace *trace, FILE *fp)
1125{ 2097{
1126 size_t printed = trace__fprintf_threads_header(fp); 2098 struct stats *stats;
1127 struct rb_node *nd; 2099 size_t printed = 0;
1128 2100 struct syscall *sc;
1129 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) { 2101 struct int_node *inode = intlist__first(ttrace->syscall_stats);
1130 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1131 struct thread_trace *ttrace = thread->priv;
1132 const char *color;
1133 double ratio;
1134
1135 if (ttrace == NULL)
1136 continue;
1137 2102
1138 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0; 2103 if (inode == NULL)
2104 return 0;
1139 2105
1140 color = PERF_COLOR_NORMAL; 2106 printed += fprintf(fp, "\n");
1141 if (ratio > 50.0) 2107
1142 color = PERF_COLOR_RED; 2108 /* each int_node is a syscall */
1143 else if (ratio > 25.0) 2109 while (inode) {
1144 color = PERF_COLOR_GREEN; 2110 stats = inode->priv;
1145 else if (ratio > 5.0) 2111 if (stats) {
1146 color = PERF_COLOR_YELLOW; 2112 double min = (double)(stats->min) / NSEC_PER_MSEC;
2113 double max = (double)(stats->max) / NSEC_PER_MSEC;
2114 double avg = avg_stats(stats);
2115 double pct;
2116 u64 n = (u64) stats->n;
2117
2118 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2119 avg /= NSEC_PER_MSEC;
2120
2121 sc = &trace->syscalls.table[inode->i];
2122 printed += fprintf(fp, "%24s %14s : ", "", sc->name);
2123 printed += fprintf(fp, "%5" PRIu64 " %8.3f %8.3f",
2124 n, min, max);
2125 printed += fprintf(fp, " %8.3f %6.2f\n", avg, pct);
2126 }
1147 2127
1148 printed += color_fprintf(fp, color, "%20s", thread->comm); 2128 inode = intlist__next(inode);
1149 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
1150 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1151 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1152 } 2129 }
1153 2130
2131 printed += fprintf(fp, "\n\n");
2132
1154 return printed; 2133 return printed;
1155} 2134}
1156 2135
2136/* struct used to pass data to per-thread function */
2137struct summary_data {
2138 FILE *fp;
2139 struct trace *trace;
2140 size_t printed;
2141};
2142
2143static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2144{
2145 struct summary_data *data = priv;
2146 FILE *fp = data->fp;
2147 size_t printed = data->printed;
2148 struct trace *trace = data->trace;
2149 struct thread_trace *ttrace = thread->priv;
2150 const char *color;
2151 double ratio;
2152
2153 if (ttrace == NULL)
2154 return 0;
2155
2156 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2157
2158 color = PERF_COLOR_NORMAL;
2159 if (ratio > 50.0)
2160 color = PERF_COLOR_RED;
2161 else if (ratio > 25.0)
2162 color = PERF_COLOR_GREEN;
2163 else if (ratio > 5.0)
2164 color = PERF_COLOR_YELLOW;
2165
2166 printed += color_fprintf(fp, color, "%20s", thread__comm_str(thread));
2167 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
2168 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
2169 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
2170 printed += thread__dump_stats(ttrace, trace, fp);
2171
2172 data->printed += printed;
2173
2174 return 0;
2175}
2176
2177static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2178{
2179 struct summary_data data = {
2180 .fp = fp,
2181 .trace = trace
2182 };
2183 data.printed = trace__fprintf_threads_header(fp);
2184
2185 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
2186
2187 return data.printed;
2188}
2189
1157static int trace__set_duration(const struct option *opt, const char *str, 2190static int trace__set_duration(const struct option *opt, const char *str,
1158 int unset __maybe_unused) 2191 int unset __maybe_unused)
1159{ 2192{
@@ -1185,10 +2218,15 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1185 const char * const trace_usage[] = { 2218 const char * const trace_usage[] = {
1186 "perf trace [<options>] [<command>]", 2219 "perf trace [<options>] [<command>]",
1187 "perf trace [<options>] -- <command> [<options>]", 2220 "perf trace [<options>] -- <command> [<options>]",
2221 "perf trace record [<options>] [<command>]",
2222 "perf trace record [<options>] -- <command> [<options>]",
1188 NULL 2223 NULL
1189 }; 2224 };
1190 struct trace trace = { 2225 struct trace trace = {
1191 .audit_machine = audit_detect_machine(), 2226 .audit = {
2227 .machine = audit_detect_machine(),
2228 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2229 },
1192 .syscalls = { 2230 .syscalls = {
1193 . max = -1, 2231 . max = -1,
1194 }, 2232 },
@@ -1203,10 +2241,14 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1203 .mmap_pages = 1024, 2241 .mmap_pages = 1024,
1204 }, 2242 },
1205 .output = stdout, 2243 .output = stdout,
2244 .show_comm = true,
1206 }; 2245 };
1207 const char *output_name = NULL; 2246 const char *output_name = NULL;
1208 const char *ev_qualifier_str = NULL; 2247 const char *ev_qualifier_str = NULL;
1209 const struct option trace_options[] = { 2248 const struct option trace_options[] = {
2249 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2250 "show the thread COMM next to its id"),
2251 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
1210 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", 2252 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1211 "list of events to trace"), 2253 "list of events to trace"),
1212 OPT_STRING('o', "output", &output_name, "file", "output file name"), 2254 OPT_STRING('o', "output", &output_name, "file", "output file name"),
@@ -1221,8 +2263,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1221 "list of cpus to monitor"), 2263 "list of cpus to monitor"),
1222 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit, 2264 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
1223 "child tasks do not inherit counters"), 2265 "child tasks do not inherit counters"),
1224 OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages, 2266 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
1225 "number of mmap data pages"), 2267 "number of mmap data pages",
2268 perf_evlist__parse_mmap_pages),
1226 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user", 2269 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
1227 "user to profile"), 2270 "user to profile"),
1228 OPT_CALLBACK(0, "duration", &trace, "float", 2271 OPT_CALLBACK(0, "duration", &trace, "float",
@@ -1230,11 +2273,18 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1230 trace__set_duration), 2273 trace__set_duration),
1231 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"), 2274 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
1232 OPT_INCR('v', "verbose", &verbose, "be more verbose"), 2275 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
2276 OPT_BOOLEAN('T', "time", &trace.full_time,
2277 "Show full timestamp, not time relative to first start"),
2278 OPT_BOOLEAN(0, "summary", &trace.summary,
2279 "Show syscall summary with statistics"),
1233 OPT_END() 2280 OPT_END()
1234 }; 2281 };
1235 int err; 2282 int err;
1236 char bf[BUFSIZ]; 2283 char bf[BUFSIZ];
1237 2284
2285 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
2286 return trace__record(argc-2, &argv[2]);
2287
1238 argc = parse_options(argc, argv, trace_options, trace_usage, 0); 2288 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
1239 2289
1240 if (output_name != NULL) { 2290 if (output_name != NULL) {
@@ -1282,9 +2332,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1282 else 2332 else
1283 err = trace__run(&trace, argc, argv); 2333 err = trace__run(&trace, argc, argv);
1284 2334
1285 if (trace.sched && !err)
1286 trace__fprintf_thread_summary(&trace, trace.output);
1287
1288out_close: 2335out_close:
1289 if (output_name != NULL) 2336 if (output_name != NULL)
1290 fclose(trace.output); 2337 fclose(trace.output);