blob: 9f2a242fa79c13dcc5b81b09472602ba09ca510e [file] [log] [blame]
Robert Richter4e319022013-06-11 17:29:18 +02001#include <traceevent/event-parse.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03003#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03004#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03005#include "util/evlist.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03006#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -06007#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03008#include "util/thread.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03009#include "util/parse-options.h"
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030010#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060011#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030012#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060013#include "util/stat.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030014
15#include <libaudit.h>
16#include <stdlib.h>
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -030017#include <sys/eventfd.h>
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030018#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030019#include <linux/futex.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030020
Ingo Molnar456857b2013-09-12 15:29:00 +020021/* For older distros: */
22#ifndef MAP_STACK
23# define MAP_STACK 0x20000
24#endif
25
26#ifndef MADV_HWPOISON
27# define MADV_HWPOISON 100
28#endif
29
30#ifndef MADV_MERGEABLE
31# define MADV_MERGEABLE 12
32#endif
33
34#ifndef MADV_UNMERGEABLE
35# define MADV_UNMERGEABLE 13
36#endif
37
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -030038struct tp_field {
39 int offset;
40 union {
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)
71{
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;
92}
93
94static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
95{
96 return sample->raw_data + field->offset;
97}
98
99static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
100{
101 field->offset = format_field->offset;
102 field->pointer = tp_field__ptr;
103 return 0;
104}
105
106struct syscall_tp {
107 struct tp_field id;
108 union {
109 struct tp_field args, ret;
110 };
111};
112
113static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
114 struct tp_field *field,
115 const char *name)
116{
117 struct format_field *format_field = perf_evsel__field(evsel, name);
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
Namhyung Kim96695d42013-11-12 08:51:45 -0300152static 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;
161 }
162
163 return -ENOMEM;
164
165out_delete:
166 free(evsel->priv);
167 evsel->priv = NULL;
168 return -ENOENT;
169}
170
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300171static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300172{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300173 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300174
175 if (evsel) {
Namhyung Kim96695d42013-11-12 08:51:45 -0300176 if (perf_evsel__init_syscall_tp(evsel, handler))
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300177 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300178 }
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;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300200 struct perf_evsel *sys_enter, *sys_exit;
201
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300202 sys_enter = perf_evsel__syscall_newtp("sys_enter", sys_enter_handler);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300203 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
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300209 sys_exit = perf_evsel__syscall_newtp("sys_exit", sys_exit_handler);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300210 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
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300231struct syscall_arg {
232 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300233 struct thread *thread;
234 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300235 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300236 u8 idx;
237 u8 mask;
238};
239
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300240struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300241 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300242 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
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300251#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
252 .offset = off, \
253 .nr_entries = ARRAY_SIZE(array), \
254 .entries = array, \
255}
256
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300257static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
258 const char *intfmt,
259 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300260{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300261 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300262 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300263
264 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300265 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300266
267 return scnprintf(bf, size, "%s", sa->entries[idx]);
268}
269
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300270static 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
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300276#define SCA_STRARRAY syscall_arg__scnprintf_strarray
277
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300278static 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
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300286static 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
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300309static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300310 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300311{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300312 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300313}
314
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300315#define SCA_HEX syscall_arg__scnprintf_hex
316
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300317static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300318 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300319{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300320 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300321
322 if (prot == PROT_NONE)
323 return scnprintf(bf, size, "NONE");
324#define P_MMAP_PROT(n) \
325 if (prot & PROT_##n) { \
326 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
327 prot &= ~PROT_##n; \
328 }
329
330 P_MMAP_PROT(EXEC);
331 P_MMAP_PROT(READ);
332 P_MMAP_PROT(WRITE);
333#ifdef PROT_SEM
334 P_MMAP_PROT(SEM);
335#endif
336 P_MMAP_PROT(GROWSDOWN);
337 P_MMAP_PROT(GROWSUP);
338#undef P_MMAP_PROT
339
340 if (prot)
341 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
342
343 return printed;
344}
345
346#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
347
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300348static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300349 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300350{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300351 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300352
353#define P_MMAP_FLAG(n) \
354 if (flags & MAP_##n) { \
355 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
356 flags &= ~MAP_##n; \
357 }
358
359 P_MMAP_FLAG(SHARED);
360 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400361#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300362 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400363#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300364 P_MMAP_FLAG(ANONYMOUS);
365 P_MMAP_FLAG(DENYWRITE);
366 P_MMAP_FLAG(EXECUTABLE);
367 P_MMAP_FLAG(FILE);
368 P_MMAP_FLAG(FIXED);
369 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600370#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300371 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600372#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300373 P_MMAP_FLAG(LOCKED);
374 P_MMAP_FLAG(NONBLOCK);
375 P_MMAP_FLAG(NORESERVE);
376 P_MMAP_FLAG(POPULATE);
377 P_MMAP_FLAG(STACK);
378#ifdef MAP_UNINITIALIZED
379 P_MMAP_FLAG(UNINITIALIZED);
380#endif
381#undef P_MMAP_FLAG
382
383 if (flags)
384 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
385
386 return printed;
387}
388
389#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
390
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300391static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300392 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300393{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300394 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300395
396 switch (behavior) {
397#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
398 P_MADV_BHV(NORMAL);
399 P_MADV_BHV(RANDOM);
400 P_MADV_BHV(SEQUENTIAL);
401 P_MADV_BHV(WILLNEED);
402 P_MADV_BHV(DONTNEED);
403 P_MADV_BHV(REMOVE);
404 P_MADV_BHV(DONTFORK);
405 P_MADV_BHV(DOFORK);
406 P_MADV_BHV(HWPOISON);
407#ifdef MADV_SOFT_OFFLINE
408 P_MADV_BHV(SOFT_OFFLINE);
409#endif
410 P_MADV_BHV(MERGEABLE);
411 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600412#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300413 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600414#endif
415#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300416 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600417#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300418#ifdef MADV_DONTDUMP
419 P_MADV_BHV(DONTDUMP);
420#endif
421#ifdef MADV_DODUMP
422 P_MADV_BHV(DODUMP);
423#endif
424#undef P_MADV_PHV
425 default: break;
426 }
427
428 return scnprintf(bf, size, "%#x", behavior);
429}
430
431#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
432
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300433static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
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
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300464static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300465{
466 enum syscall_futex_args {
467 SCF_UADDR = (1 << 0),
468 SCF_OP = (1 << 1),
469 SCF_VAL = (1 << 2),
470 SCF_TIMEOUT = (1 << 3),
471 SCF_UADDR2 = (1 << 4),
472 SCF_VAL3 = (1 << 5),
473 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300474 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300475 int cmd = op & FUTEX_CMD_MASK;
476 size_t printed = 0;
477
478 switch (cmd) {
479#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300480 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
481 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
482 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
483 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
484 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
485 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300486 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300487 P_FUTEX_OP(LOCK_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;
489 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
490 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
491 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300492 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
493 default: printed = scnprintf(bf, size, "%#x", cmd); break;
494 }
495
496 if (op & FUTEX_PRIVATE_FLAG)
497 printed += scnprintf(bf + printed, size - printed, "|PRIV");
498
499 if (op & FUTEX_CLOCK_REALTIME)
500 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
501
502 return printed;
503}
504
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300505#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
506
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300507static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
508static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300509
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300510static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
511static DEFINE_STRARRAY(itimers);
512
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300513static 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);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300522
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300523static 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
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300531static 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
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300538static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
539static DEFINE_STRARRAY(sighow);
540
David Ahern4f8c1b72013-09-22 19:45:00 -0600541static 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
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300547static 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
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300557#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
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300604#ifndef MSG_PROBE
605#define MSG_PROBE 0x10
606#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600607#ifndef MSG_WAITFORONE
608#define MSG_WAITFORONE 0x10000
609#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300610#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
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300661static 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
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300688static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300689 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300690{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300691 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300692
693 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300694 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300695
696 if (flags == 0)
697 return scnprintf(bf, size, "RDONLY");
698#define P_FLAG(n) \
699 if (flags & O_##n) { \
700 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
701 flags &= ~O_##n; \
702 }
703
704 P_FLAG(APPEND);
705 P_FLAG(ASYNC);
706 P_FLAG(CLOEXEC);
707 P_FLAG(CREAT);
708 P_FLAG(DIRECT);
709 P_FLAG(DIRECTORY);
710 P_FLAG(EXCL);
711 P_FLAG(LARGEFILE);
712 P_FLAG(NOATIME);
713 P_FLAG(NOCTTY);
714#ifdef O_NONBLOCK
715 P_FLAG(NONBLOCK);
716#elif O_NDELAY
717 P_FLAG(NDELAY);
718#endif
719#ifdef O_PATH
720 P_FLAG(PATH);
721#endif
722 P_FLAG(RDWR);
723#ifdef O_DSYNC
724 if ((flags & O_SYNC) == O_SYNC)
725 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
726 else {
727 P_FLAG(DSYNC);
728 }
729#else
730 P_FLAG(SYNC);
731#endif
732 P_FLAG(TRUNC);
733 P_FLAG(WRONLY);
734#undef P_FLAG
735
736 if (flags)
737 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
738
739 return printed;
740}
741
742#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
743
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300744static 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
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300770static 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
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300793static 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
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300838#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
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300860#define STRARRAY(arg, name, array) \
861 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
862 .arg_parm = { [arg] = &strarray__##array, }
863
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300864static struct syscall_fmt {
865 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300866 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300867 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300868 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300869 bool errmsg;
870 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300871 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300872} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300873 { .name = "access", .errmsg = true,
874 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300875 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300876 { .name = "brk", .hexret = true,
877 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600878 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300879 { .name = "close", .errmsg = true,
880 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300881 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300882 { .name = "dup", .errmsg = true,
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 */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300888 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300889 { .name = "eventfd2", .errmsg = true,
890 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300891 { .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 */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300913 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300914 .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 */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300928 { .name = "futex", .errmsg = true,
929 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300930 { .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 */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300936 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
937 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300938 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300939 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300940 [1] = SCA_STRHEXARRAY, /* cmd */
941 [2] = SCA_HEX, /* arg */ },
942 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300943 { .name = "kill", .errmsg = true,
944 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300945 { .name = "linkat", .errmsg = true,
946 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
947 { .name = "lseek", .errmsg = true,
948 .arg_scnprintf = { [0] = SCA_FD, /* fd */
949 [2] = SCA_STRARRAY, /* whence */ },
950 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300951 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300952 { .name = "madvise", .errmsg = true,
953 .arg_scnprintf = { [0] = SCA_HEX, /* start */
954 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300955 { .name = "mkdirat", .errmsg = true,
956 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
957 { .name = "mknodat", .errmsg = true,
958 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300959 { .name = "mlock", .errmsg = true,
960 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
961 { .name = "mlockall", .errmsg = true,
962 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300963 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300964 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300965 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +0900966 [3] = SCA_MMAP_FLAGS, /* flags */
967 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300968 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300969 .arg_scnprintf = { [0] = SCA_HEX, /* start */
970 [2] = SCA_MMAP_PROT, /* prot */ }, },
971 { .name = "mremap", .hexret = true,
972 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
973 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300974 { .name = "munlock", .errmsg = true,
975 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300976 { .name = "munmap", .errmsg = true,
977 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300978 { .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 */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300982 { .name = "open", .errmsg = true,
983 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300984 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300985 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
986 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300987 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300988 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
989 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300990 { .name = "pipe2", .errmsg = true,
991 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300992 { .name = "poll", .errmsg = true, .timeout = true, },
993 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300994 { .name = "pread", .errmsg = true, .alias = "pread64",
995 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
996 { .name = "preadv", .errmsg = true, .alias = "pread",
997 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300998 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300999 { .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 */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001009 { .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 */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001015 { .name = "renameat", .errmsg = true,
1016 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001017 { .name = "rt_sigaction", .errmsg = true,
1018 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001019 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001020 { .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 */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001024 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001025 { .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 */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001031 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1032 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001033 { .name = "shutdown", .errmsg = true,
1034 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001035 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001036 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1037 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001038 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001039 { .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 */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001043 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001044 { .name = "symlinkat", .errmsg = true,
1045 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001046 { .name = "tgkill", .errmsg = true,
1047 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1048 { .name = "tkill", .errmsg = true,
1049 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001050 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001051 { .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 */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001059};
1060
1061static int syscall_fmt__cmp(const void *name, const void *fmtp)
1062{
1063 const struct syscall_fmt *fmt = fmtp;
1064 return strcmp(name, fmt->name);
1065}
1066
1067static struct syscall_fmt *syscall_fmt__find(const char *name)
1068{
1069 const int nmemb = ARRAY_SIZE(syscall_fmts);
1070 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1071}
1072
1073struct syscall {
1074 struct event_format *tp_format;
1075 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001076 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001077 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001078 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001079 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001080};
1081
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001082static size_t fprintf_duration(unsigned long t, FILE *fp)
1083{
1084 double duration = (double)t / NSEC_PER_MSEC;
1085 size_t printed = fprintf(fp, "(");
1086
1087 if (duration >= 1.0)
1088 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1089 else if (duration >= 0.01)
1090 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1091 else
1092 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001093 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001094}
1095
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001096struct thread_trace {
1097 u64 entry_time;
1098 u64 exit_time;
1099 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001100 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001101 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001102 double runtime_ms;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001103 struct {
1104 int max;
1105 char **table;
1106 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001107
1108 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001109};
1110
1111static struct thread_trace *thread_trace__new(void)
1112{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001113 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1114
1115 if (ttrace)
1116 ttrace->paths.max = -1;
1117
David Ahernbf2575c2013-10-08 21:26:53 -06001118 ttrace->syscall_stats = intlist__new(NULL);
1119
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001120 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001121}
1122
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001123static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001124{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001125 struct thread_trace *ttrace;
1126
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001127 if (thread == NULL)
1128 goto fail;
1129
1130 if (thread->priv == NULL)
1131 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001132
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001133 if (thread->priv == NULL)
1134 goto fail;
1135
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001136 ttrace = thread->priv;
1137 ++ttrace->nr_events;
1138
1139 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001140fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001141 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001142 "WARNING: not enough memory, dropping samples!\n");
1143 return NULL;
1144}
1145
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001146struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001147 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001148 struct {
1149 int machine;
1150 int open_id;
1151 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001152 struct {
1153 int max;
1154 struct syscall *table;
1155 } syscalls;
1156 struct perf_record_opts opts;
David Ahern8fb598e2013-09-28 13:13:00 -06001157 struct machine *host;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001158 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -06001159 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001160 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001161 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001162 struct strlist *ev_qualifier;
1163 bool not_ev_qualifier;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001164 bool live;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001165 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -06001166 struct intlist *tid_list;
1167 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001168 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001169 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001170 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001171 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001172 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001173 bool show_tool_stats;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001174 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001175 double runtime_ms;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001176 struct {
1177 u64 vfs_getname, proc_getname;
1178 } stats;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001179};
1180
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001181static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001182{
1183 struct thread_trace *ttrace = thread->priv;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001184
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
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001207static 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
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001233static const char *thread__fd_path(struct thread *thread, int fd,
1234 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001235{
1236 struct thread_trace *ttrace = thread->priv;
1237
1238 if (ttrace == NULL)
1239 return NULL;
1240
1241 if (fd < 0)
1242 return NULL;
1243
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001244 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 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001251
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);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001260 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001261
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
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001283static bool trace__filter_duration(struct trace *trace, double t)
1284{
1285 return t < (trace->duration_filter * NSEC_PER_MSEC);
1286}
1287
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001288static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1289{
1290 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1291
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001292 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001293}
1294
Namhyung Kimf15eb532012-10-05 14:02:16 +09001295static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001296static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001297
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001298static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001299{
1300 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001301 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001302}
1303
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001304static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001305 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001306{
1307 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001308 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001309
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001310 if (trace->multiple_threads) {
1311 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001312 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001313 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001314 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001315
1316 return printed;
1317}
1318
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001319static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001320 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001321{
1322 int ret = 0;
1323
1324 switch (event->header.type) {
1325 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001326 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001327 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001328 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001329 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001330 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001331 break;
1332 }
1333
1334 return ret;
1335}
1336
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001337static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001338 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001339 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001340 struct machine *machine)
1341{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001342 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001343 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001344}
1345
1346static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1347{
1348 int err = symbol__init();
1349
1350 if (err)
1351 return err;
1352
David Ahern8fb598e2013-09-28 13:13:00 -06001353 trace->host = machine__new_host();
1354 if (trace->host == NULL)
1355 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001356
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001357 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
1358 evlist->threads, trace__tool_process, false);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001359 if (err)
1360 symbol__exit();
1361
1362 return err;
1363}
1364
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001365static int syscall__set_arg_fmts(struct syscall *sc)
1366{
1367 struct format_field *field;
1368 int idx = 0;
1369
1370 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1371 if (sc->arg_scnprintf == NULL)
1372 return -1;
1373
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001374 if (sc->fmt)
1375 sc->arg_parm = sc->fmt->arg_parm;
1376
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001377 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001378 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1379 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1380 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001381 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1382 ++idx;
1383 }
1384
1385 return 0;
1386}
1387
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001388static int trace__read_syscall_info(struct trace *trace, int id)
1389{
1390 char tp_name[128];
1391 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001392 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001393
1394 if (name == NULL)
1395 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001396
1397 if (id > trace->syscalls.max) {
1398 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1399
1400 if (nsyscalls == NULL)
1401 return -1;
1402
1403 if (trace->syscalls.max != -1) {
1404 memset(nsyscalls + trace->syscalls.max + 1, 0,
1405 (id - trace->syscalls.max) * sizeof(*sc));
1406 } else {
1407 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1408 }
1409
1410 trace->syscalls.table = nsyscalls;
1411 trace->syscalls.max = id;
1412 }
1413
1414 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001415 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001416
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001417 if (trace->ev_qualifier) {
1418 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1419
1420 if (!(in ^ trace->not_ev_qualifier)) {
1421 sc->filtered = true;
1422 /*
1423 * No need to do read tracepoint information since this will be
1424 * filtered out.
1425 */
1426 return 0;
1427 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001428 }
1429
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001430 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001431
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001432 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
1433 sc->tp_format = event_format__new("syscalls", tp_name);
1434
1435 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1436 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
1437 sc->tp_format = event_format__new("syscalls", tp_name);
1438 }
1439
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001440 if (sc->tp_format == NULL)
1441 return -1;
1442
1443 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001444}
1445
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001446static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001447 unsigned long *args, struct trace *trace,
1448 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001449{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001450 size_t printed = 0;
1451
1452 if (sc->tp_format != NULL) {
1453 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001454 u8 bit = 1;
1455 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001456 .idx = 0,
1457 .mask = 0,
1458 .trace = trace,
1459 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001460 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001461
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001462 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001463 field = field->next, ++arg.idx, bit <<= 1) {
1464 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001465 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001466 /*
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]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001475 continue;
1476
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001477 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001478 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001479 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1480 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001481 if (sc->arg_parm)
1482 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001483 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1484 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001485 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001486 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001487 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001488 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001489 }
1490 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001491 int i = 0;
1492
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001493 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001494 printed += scnprintf(bf + printed, size - printed,
1495 "%sarg%d: %ld",
1496 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001497 ++i;
1498 }
1499 }
1500
1501 return printed;
1502}
1503
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001504typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1505 struct perf_sample *sample);
1506
1507static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001508 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001509{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001510
1511 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001512
1513 /*
1514 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1515 * before that, leaving at a higher verbosity level till that is
1516 * explained. Reproduced with plain ftrace with:
1517 *
1518 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1519 * grep "NR -1 " /t/trace_pipe
1520 *
1521 * After generating some load on the machine.
1522 */
1523 if (verbose > 1) {
1524 static u64 n;
1525 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1526 id, perf_evsel__name(evsel), ++n);
1527 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001528 return NULL;
1529 }
1530
1531 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1532 trace__read_syscall_info(trace, id))
1533 goto out_cant_read;
1534
1535 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1536 goto out_cant_read;
1537
1538 return &trace->syscalls.table[id];
1539
1540out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001541 if (verbose) {
1542 fprintf(trace->output, "Problems reading syscall %d", id);
1543 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1544 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1545 fputs(" information\n", trace->output);
1546 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001547 return NULL;
1548}
1549
David Ahernbf2575c2013-10-08 21:26:53 -06001550static 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
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001576static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1577 struct perf_sample *sample)
1578{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001579 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001580 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001581 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001582 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001583 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001584 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001585 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001586
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001587 if (sc == NULL)
1588 return -1;
1589
1590 if (sc->filtered)
1591 return 0;
1592
David Ahern8fb598e2013-09-28 13:13:00 -06001593 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001594 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001595 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001596 return -1;
1597
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001598 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001599 ttrace = thread->priv;
1600
1601 if (ttrace->entry_str == NULL) {
1602 ttrace->entry_str = malloc(1024);
1603 if (!ttrace->entry_str)
1604 return -1;
1605 }
1606
1607 ttrace->entry_time = sample->time;
1608 msg = ttrace->entry_str;
1609 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1610
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001611 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1612 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001613
1614 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001615 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001616 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1617 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001618 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001619 } else
1620 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001621
1622 return 0;
1623}
1624
1625static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1626 struct perf_sample *sample)
1627{
1628 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001629 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001630 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001631 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001632 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001633 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001634
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001635 if (sc == NULL)
1636 return -1;
1637
1638 if (sc->filtered)
1639 return 0;
1640
David Ahern8fb598e2013-09-28 13:13:00 -06001641 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001642 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001643 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001644 return -1;
1645
David Ahernbf2575c2013-10-08 21:26:53 -06001646 if (trace->summary)
1647 thread__update_stats(ttrace, id, sample);
1648
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001649 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001650
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001651 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 }
1656
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001657 ttrace = thread->priv;
1658
1659 ttrace->exit_time = sample->time;
1660
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001661 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001662 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001663 if (trace__filter_duration(trace, duration))
1664 goto out;
1665 } else if (trace->duration_filter)
1666 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001667
David Ahernfd2eaba2013-11-12 09:31:15 -07001668 if (trace->summary_only)
1669 goto out;
1670
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001671 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001672
1673 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001674 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001675 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001676 fprintf(trace->output, " ... [");
1677 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1678 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001679 }
1680
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001681 if (sc->fmt == NULL) {
1682signed_print:
1683 fprintf(trace->output, ") = %d", ret);
1684 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001685 char bf[256];
1686 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1687 *e = audit_errno_to_name(-ret);
1688
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001689 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001690 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001691 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001692 else if (sc->fmt->hexret)
1693 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001694 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001695 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001696
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001697 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001698out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001699 ttrace->entry_pending = false;
1700
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001701 return 0;
1702}
1703
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001704static 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
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001711static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1712 struct perf_sample *sample)
1713{
1714 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1715 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001716 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001717 sample->pid,
1718 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001719 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001720
1721 if (ttrace == NULL)
1722 goto out_dump;
1723
1724 ttrace->runtime_ms += runtime_ms;
1725 trace->runtime_ms += runtime_ms;
1726 return 0;
1727
1728out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001729 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001730 evsel->name,
1731 perf_evsel__strval(evsel, sample, "comm"),
1732 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1733 runtime,
1734 perf_evsel__intval(evsel, sample, "vruntime"));
1735 return 0;
1736}
1737
David Ahernbdc89662013-08-28 22:29:53 -06001738static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1739{
1740 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1741 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1742 return false;
1743
1744 if (trace->pid_list || trace->tid_list)
1745 return true;
1746
1747 return false;
1748}
1749
David Ahern6810fc92013-08-28 22:29:52 -06001750static int trace__process_sample(struct perf_tool *tool,
1751 union perf_event *event __maybe_unused,
1752 struct perf_sample *sample,
1753 struct perf_evsel *evsel,
1754 struct machine *machine __maybe_unused)
1755{
1756 struct trace *trace = container_of(tool, struct trace, tool);
1757 int err = 0;
1758
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001759 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001760
David Ahernbdc89662013-08-28 22:29:53 -06001761 if (skip_sample(trace, sample))
1762 return 0;
1763
David Ahern4bb09192013-09-04 12:37:43 -06001764 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001765 trace->base_time = sample->time;
1766
1767 if (handler)
1768 handler(trace, evsel, sample);
1769
1770 return err;
1771}
1772
David Ahernbdc89662013-08-28 22:29:53 -06001773static int parse_target_str(struct trace *trace)
1774{
1775 if (trace->opts.target.pid) {
1776 trace->pid_list = intlist__new(trace->opts.target.pid);
1777 if (trace->pid_list == NULL) {
1778 pr_err("Error parsing process id string\n");
1779 return -EINVAL;
1780 }
1781 }
1782
1783 if (trace->opts.target.tid) {
1784 trace->tid_list = intlist__new(trace->opts.target.tid);
1785 if (trace->tid_list == NULL) {
1786 pr_err("Error parsing thread id string\n");
1787 return -EINVAL;
1788 }
1789 }
1790
1791 return 0;
1792}
1793
David Ahern5e2485b2013-09-28 13:13:01 -06001794static 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
David Ahernbf2575c2013-10-08 21:26:53 -06001821static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
1822
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001823static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
1824{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03001825 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001826 if (evsel == NULL)
1827 return;
1828
1829 if (perf_evsel__field(evsel, "pathname") == NULL) {
1830 perf_evsel__delete(evsel);
1831 return;
1832 }
1833
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001834 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001835 perf_evlist__add(evlist, evsel);
1836}
1837
Namhyung Kimf15eb532012-10-05 14:02:16 +09001838static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001839{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001840 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001841 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001842 int err = -1, i;
1843 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001844 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001845
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001846 trace->live = true;
1847
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001848 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001849 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001850 goto out;
1851 }
1852
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001853 if (perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, trace__sys_exit))
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301854 goto out_error_tp;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001855
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001856 perf_evlist__add_vfs_getname(evlist);
1857
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001858 if (trace->sched &&
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301859 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1860 trace__sched_stat_runtime))
1861 goto out_error_tp;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001862
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001863 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1864 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001865 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001866 goto out_delete_evlist;
1867 }
1868
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001869 err = trace__symbols_init(trace, evlist);
1870 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001871 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001872 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001873 }
1874
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001875 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001876
Namhyung Kimf15eb532012-10-05 14:02:16 +09001877 signal(SIGCHLD, sig_handler);
1878 signal(SIGINT, sig_handler);
1879
1880 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001881 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001882 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001883 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001884 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001885 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001886 }
1887 }
1888
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001889 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03001890 if (err < 0)
1891 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001892
Jiri Olsaf8850372013-11-28 17:57:22 +01001893 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001894 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001895 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001896 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001897 }
1898
1899 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001900
1901 if (forks)
1902 perf_evlist__start_workload(evlist);
1903
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001904 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001905again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001906 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001907
1908 for (i = 0; i < evlist->nr_mmaps; i++) {
1909 union perf_event *event;
1910
1911 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1912 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001913 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001914 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001915
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001916 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001917
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001918 err = perf_evlist__parse_sample(evlist, event, &sample);
1919 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001920 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001921 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001922 }
1923
David Ahern4bb09192013-09-04 12:37:43 -06001924 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001925 trace->base_time = sample.time;
1926
1927 if (type != PERF_RECORD_SAMPLE) {
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001928 trace__process_event(trace, trace->host, event, &sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001929 continue;
1930 }
1931
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001932 evsel = perf_evlist__id2evsel(evlist, sample.id);
1933 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001934 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001935 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001936 }
1937
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001938 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001939 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001940 perf_evsel__name(evsel), sample.tid,
1941 sample.cpu, sample.raw_size);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001942 goto next_event;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001943 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001944
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001945 handler = evsel->handler;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001946 handler(trace, evsel, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001947next_event:
1948 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001949
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001950 if (interrupted)
1951 goto out_disable;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001952 }
1953 }
1954
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001955 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001956 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001957
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001958 if (poll(evlist->pollfd, evlist->nr_fds, timeout) > 0)
1959 goto again;
1960 } else {
1961 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001962 }
1963
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001964out_disable:
1965 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001966
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001967 if (!err) {
1968 if (trace->summary)
1969 trace__fprintf_thread_summary(trace, trace->output);
1970
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 }
David Ahernbf2575c2013-10-08 21:26:53 -06001979
Namhyung Kim3beb0862013-03-15 14:48:50 +09001980 perf_evlist__munmap(evlist);
1981out_close_evlist:
1982 perf_evlist__close(evlist);
1983out_delete_maps:
1984 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001985out_delete_evlist:
1986 perf_evlist__delete(evlist);
1987out:
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001988 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001989 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03001990{
1991 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03001992
1993out_error_tp:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03001994 perf_evlist__strerror_tp(evlist, errno, errbuf, sizeof(errbuf));
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03001995 goto out_error;
1996
1997out_error_open:
1998 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
1999
2000out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002001 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302002 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002003}
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002004}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002005
David Ahern6810fc92013-08-28 22:29:52 -06002006static int trace__replay(struct trace *trace)
2007{
2008 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002009 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002010 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002011 struct perf_data_file file = {
2012 .path = input_name,
2013 .mode = PERF_DATA_MODE_READ,
2014 };
David Ahern6810fc92013-08-28 22:29:52 -06002015 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002016 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002017 int err = -1;
2018
2019 trace->tool.sample = trace__process_sample;
2020 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002021 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002022 trace->tool.comm = perf_event__process_comm;
2023 trace->tool.exit = perf_event__process_exit;
2024 trace->tool.fork = perf_event__process_fork;
2025 trace->tool.attr = perf_event__process_attr;
2026 trace->tool.tracing_data = perf_event__process_tracing_data;
2027 trace->tool.build_id = perf_event__process_build_id;
2028
2029 trace->tool.ordered_samples = true;
2030 trace->tool.ordering_requires_timestamps = true;
2031
2032 /* add tid to output */
2033 trace->multiple_threads = true;
2034
2035 if (symbol__init() < 0)
2036 return -1;
2037
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002038 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002039 if (session == NULL)
2040 return -ENOMEM;
2041
David Ahern8fb598e2013-09-28 13:13:00 -06002042 trace->host = &session->machines.host;
2043
David Ahern6810fc92013-08-28 22:29:52 -06002044 err = perf_session__set_tracepoints_handlers(session, handlers);
2045 if (err)
2046 goto out;
2047
Namhyung Kim003824e2013-11-12 15:25:00 +09002048 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2049 "raw_syscalls:sys_enter");
2050 if (evsel == NULL) {
2051 pr_err("Data file does not have raw_syscalls:sys_enter event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002052 goto out;
2053 }
2054
Namhyung Kim003824e2013-11-12 15:25:00 +09002055 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");
2065 goto out;
2066 }
2067
2068 if (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2069 perf_evsel__init_sc_tp_uint_field(evsel, ret)) {
2070 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002071 goto out;
2072 }
2073
David Ahernbdc89662013-08-28 22:29:53 -06002074 err = parse_target_str(trace);
2075 if (err != 0)
2076 goto out;
2077
David Ahern6810fc92013-08-28 22:29:52 -06002078 setup_pager();
2079
2080 err = perf_session__process_events(session, &trace->tool);
2081 if (err)
2082 pr_err("Failed to process events, error %d", err);
2083
David Ahernbf2575c2013-10-08 21:26:53 -06002084 else if (trace->summary)
2085 trace__fprintf_thread_summary(trace, trace->output);
2086
David Ahern6810fc92013-08-28 22:29:52 -06002087out:
2088 perf_session__delete(session);
2089
2090 return err;
2091}
2092
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002093static size_t trace__fprintf_threads_header(FILE *fp)
2094{
2095 size_t printed;
2096
Pekka Enberg99ff7152013-11-12 16:42:14 +02002097 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002098
2099 return printed;
2100}
2101
2102static size_t thread__dump_stats(struct thread_trace *ttrace,
2103 struct trace *trace, FILE *fp)
2104{
2105 struct stats *stats;
2106 size_t printed = 0;
2107 struct syscall *sc;
2108 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2109
2110 if (inode == NULL)
2111 return 0;
2112
2113 printed += fprintf(fp, "\n");
2114
Pekka Enberg27a778b2013-11-13 14:21:48 +02002115 printed += fprintf(fp, " syscall calls min avg max stddev\n");
2116 printed += fprintf(fp, " (msec) (msec) (msec) (%%)\n");
2117 printed += fprintf(fp, " --------------- -------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002118
David Ahernbf2575c2013-10-08 21:26:53 -06002119 /* 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];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002133 printed += fprintf(fp, " %-15s", sc->name);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002134 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f",
Pekka Enberg7f7a4132013-11-12 16:10:10 +02002135 n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002136 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002137 }
2138
2139 inode = intlist__next(inode);
2140 }
2141
2142 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002143
2144 return printed;
2145}
2146
David Ahern896cbb52013-09-28 13:12:59 -06002147/* 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;
David Ahern896cbb52013-09-28 13:12:59 -06002161 double ratio;
2162
2163 if (ttrace == NULL)
2164 return 0;
2165
2166 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2167
Pekka Enberg15e65c62013-11-14 18:43:30 +02002168 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002169 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002170 printed += fprintf(fp, "%.1f%%", ratio);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002171 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002172 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002173
2174 data->printed += printed;
2175
2176 return 0;
2177}
2178
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002179static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2180{
David Ahern896cbb52013-09-28 13:12:59 -06002181 struct summary_data data = {
2182 .fp = fp,
2183 .trace = trace
2184 };
2185 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002186
David Ahern896cbb52013-09-28 13:12:59 -06002187 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002188
David Ahern896cbb52013-09-28 13:12:59 -06002189 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002190}
2191
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002192static int trace__set_duration(const struct option *opt, const char *str,
2193 int unset __maybe_unused)
2194{
2195 struct trace *trace = opt->value;
2196
2197 trace->duration_filter = atof(str);
2198 return 0;
2199}
2200
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002201static int trace__open_output(struct trace *trace, const char *filename)
2202{
2203 struct stat st;
2204
2205 if (!stat(filename, &st) && st.st_size) {
2206 char oldname[PATH_MAX];
2207
2208 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2209 unlink(oldname);
2210 rename(filename, oldname);
2211 }
2212
2213 trace->output = fopen(filename, "w");
2214
2215 return trace->output == NULL ? -errno : 0;
2216}
2217
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002218int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2219{
2220 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002221 "perf trace [<options>] [<command>]",
2222 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002223 "perf trace record [<options>] [<command>]",
2224 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002225 NULL
2226 };
2227 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002228 .audit = {
2229 .machine = audit_detect_machine(),
2230 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2231 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002232 .syscalls = {
2233 . max = -1,
2234 },
2235 .opts = {
2236 .target = {
2237 .uid = UINT_MAX,
2238 .uses_mmap = true,
2239 },
2240 .user_freq = UINT_MAX,
2241 .user_interval = ULLONG_MAX,
2242 .no_delay = true,
2243 .mmap_pages = 1024,
2244 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002245 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002246 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002247 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002248 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002249 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002250 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002251 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2252 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002253 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002254 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
2255 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002256 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002257 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002258 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2259 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002260 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002261 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002262 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002263 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002264 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002265 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002266 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002267 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002268 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2269 "number of mmap data pages",
2270 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002271 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002272 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002273 OPT_CALLBACK(0, "duration", &trace, "float",
2274 "show only events with duration > N.M ms",
2275 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002276 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002277 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002278 OPT_BOOLEAN('T', "time", &trace.full_time,
2279 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002280 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2281 "Show only syscall summary with statistics"),
2282 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2283 "Show all syscalls and summary with statistics"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002284 OPT_END()
2285 };
2286 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002287 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002288
David Ahern5e2485b2013-09-28 13:13:01 -06002289 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
2290 return trace__record(argc-2, &argv[2]);
2291
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002292 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002293
David Ahernfd2eaba2013-11-12 09:31:15 -07002294 /* summary_only implies summary option, but don't overwrite summary if set */
2295 if (trace.summary_only)
2296 trace.summary = trace.summary_only;
2297
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002298 if (output_name != NULL) {
2299 err = trace__open_output(&trace, output_name);
2300 if (err < 0) {
2301 perror("failed to create output file");
2302 goto out;
2303 }
2304 }
2305
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002306 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002307 const char *s = ev_qualifier_str;
2308
2309 trace.not_ev_qualifier = *s == '!';
2310 if (trace.not_ev_qualifier)
2311 ++s;
2312 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002313 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002314 fputs("Not enough memory to parse event qualifier",
2315 trace.output);
2316 err = -ENOMEM;
2317 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002318 }
2319 }
2320
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002321 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002322 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002323 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002324 fprintf(trace.output, "%s", bf);
2325 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002326 }
2327
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002328 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002329 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002330 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002331 fprintf(trace.output, "%s", bf);
2332 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002333 }
2334
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002335 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002336 trace.opts.target.system_wide = true;
2337
David Ahern6810fc92013-08-28 22:29:52 -06002338 if (input_name)
2339 err = trace__replay(&trace);
2340 else
2341 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002342
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002343out_close:
2344 if (output_name != NULL)
2345 fclose(trace.output);
2346out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002347 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002348}