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