blob: 68943cad70d426de63f24b4e1edd5d102399f33d [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
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300152static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300153{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300154 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300155
156 if (evsel) {
157 evsel->priv = malloc(sizeof(struct syscall_tp));
158
159 if (evsel->priv == NULL)
160 goto out_delete;
161
162 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
163 goto out_delete;
164
165 evsel->handler = handler;
166 }
167
168 return evsel;
169
170out_delete:
171 perf_evsel__delete_priv(evsel);
172 return NULL;
173}
174
175#define perf_evsel__sc_tp_uint(evsel, name, sample) \
176 ({ struct syscall_tp *fields = evsel->priv; \
177 fields->name.integer(&fields->name, sample); })
178
179#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
180 ({ struct syscall_tp *fields = evsel->priv; \
181 fields->name.pointer(&fields->name, sample); })
182
183static int perf_evlist__add_syscall_newtp(struct perf_evlist *evlist,
184 void *sys_enter_handler,
185 void *sys_exit_handler)
186{
187 int ret = -1;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300188 struct perf_evsel *sys_enter, *sys_exit;
189
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300190 sys_enter = perf_evsel__syscall_newtp("sys_enter", sys_enter_handler);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300191 if (sys_enter == NULL)
192 goto out;
193
194 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
195 goto out_delete_sys_enter;
196
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300197 sys_exit = perf_evsel__syscall_newtp("sys_exit", sys_exit_handler);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300198 if (sys_exit == NULL)
199 goto out_delete_sys_enter;
200
201 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
202 goto out_delete_sys_exit;
203
204 perf_evlist__add(evlist, sys_enter);
205 perf_evlist__add(evlist, sys_exit);
206
207 ret = 0;
208out:
209 return ret;
210
211out_delete_sys_exit:
212 perf_evsel__delete_priv(sys_exit);
213out_delete_sys_enter:
214 perf_evsel__delete_priv(sys_enter);
215 goto out;
216}
217
218
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300219struct syscall_arg {
220 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300221 struct thread *thread;
222 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300223 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300224 u8 idx;
225 u8 mask;
226};
227
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300228struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300229 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300230 int nr_entries;
231 const char **entries;
232};
233
234#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
235 .nr_entries = ARRAY_SIZE(array), \
236 .entries = array, \
237}
238
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300239#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
240 .offset = off, \
241 .nr_entries = ARRAY_SIZE(array), \
242 .entries = array, \
243}
244
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300245static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
246 const char *intfmt,
247 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300248{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300249 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300250 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300251
252 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300253 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300254
255 return scnprintf(bf, size, "%s", sa->entries[idx]);
256}
257
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300258static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
259 struct syscall_arg *arg)
260{
261 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
262}
263
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300264#define SCA_STRARRAY syscall_arg__scnprintf_strarray
265
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300266static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
267 struct syscall_arg *arg)
268{
269 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
270}
271
272#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
273
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300274static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
275 struct syscall_arg *arg);
276
277#define SCA_FD syscall_arg__scnprintf_fd
278
279static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
280 struct syscall_arg *arg)
281{
282 int fd = arg->val;
283
284 if (fd == AT_FDCWD)
285 return scnprintf(bf, size, "CWD");
286
287 return syscall_arg__scnprintf_fd(bf, size, arg);
288}
289
290#define SCA_FDAT syscall_arg__scnprintf_fd_at
291
292static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
293 struct syscall_arg *arg);
294
295#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
296
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300297static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300298 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300299{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300300 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300301}
302
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300303#define SCA_HEX syscall_arg__scnprintf_hex
304
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300305static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300306 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300307{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300308 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300309
310 if (prot == PROT_NONE)
311 return scnprintf(bf, size, "NONE");
312#define P_MMAP_PROT(n) \
313 if (prot & PROT_##n) { \
314 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
315 prot &= ~PROT_##n; \
316 }
317
318 P_MMAP_PROT(EXEC);
319 P_MMAP_PROT(READ);
320 P_MMAP_PROT(WRITE);
321#ifdef PROT_SEM
322 P_MMAP_PROT(SEM);
323#endif
324 P_MMAP_PROT(GROWSDOWN);
325 P_MMAP_PROT(GROWSUP);
326#undef P_MMAP_PROT
327
328 if (prot)
329 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
330
331 return printed;
332}
333
334#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
335
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300336static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300337 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300338{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300339 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300340
341#define P_MMAP_FLAG(n) \
342 if (flags & MAP_##n) { \
343 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
344 flags &= ~MAP_##n; \
345 }
346
347 P_MMAP_FLAG(SHARED);
348 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400349#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300350 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400351#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300352 P_MMAP_FLAG(ANONYMOUS);
353 P_MMAP_FLAG(DENYWRITE);
354 P_MMAP_FLAG(EXECUTABLE);
355 P_MMAP_FLAG(FILE);
356 P_MMAP_FLAG(FIXED);
357 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600358#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300359 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600360#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300361 P_MMAP_FLAG(LOCKED);
362 P_MMAP_FLAG(NONBLOCK);
363 P_MMAP_FLAG(NORESERVE);
364 P_MMAP_FLAG(POPULATE);
365 P_MMAP_FLAG(STACK);
366#ifdef MAP_UNINITIALIZED
367 P_MMAP_FLAG(UNINITIALIZED);
368#endif
369#undef P_MMAP_FLAG
370
371 if (flags)
372 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
373
374 return printed;
375}
376
377#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
378
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300379static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300380 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300381{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300382 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300383
384 switch (behavior) {
385#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
386 P_MADV_BHV(NORMAL);
387 P_MADV_BHV(RANDOM);
388 P_MADV_BHV(SEQUENTIAL);
389 P_MADV_BHV(WILLNEED);
390 P_MADV_BHV(DONTNEED);
391 P_MADV_BHV(REMOVE);
392 P_MADV_BHV(DONTFORK);
393 P_MADV_BHV(DOFORK);
394 P_MADV_BHV(HWPOISON);
395#ifdef MADV_SOFT_OFFLINE
396 P_MADV_BHV(SOFT_OFFLINE);
397#endif
398 P_MADV_BHV(MERGEABLE);
399 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600400#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300401 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600402#endif
403#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300404 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600405#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300406#ifdef MADV_DONTDUMP
407 P_MADV_BHV(DONTDUMP);
408#endif
409#ifdef MADV_DODUMP
410 P_MADV_BHV(DODUMP);
411#endif
412#undef P_MADV_PHV
413 default: break;
414 }
415
416 return scnprintf(bf, size, "%#x", behavior);
417}
418
419#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
420
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300421static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
422 struct syscall_arg *arg)
423{
424 int printed = 0, op = arg->val;
425
426 if (op == 0)
427 return scnprintf(bf, size, "NONE");
428#define P_CMD(cmd) \
429 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
430 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
431 op &= ~LOCK_##cmd; \
432 }
433
434 P_CMD(SH);
435 P_CMD(EX);
436 P_CMD(NB);
437 P_CMD(UN);
438 P_CMD(MAND);
439 P_CMD(RW);
440 P_CMD(READ);
441 P_CMD(WRITE);
442#undef P_OP
443
444 if (op)
445 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
446
447 return printed;
448}
449
450#define SCA_FLOCK syscall_arg__scnprintf_flock
451
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300452static 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 -0300453{
454 enum syscall_futex_args {
455 SCF_UADDR = (1 << 0),
456 SCF_OP = (1 << 1),
457 SCF_VAL = (1 << 2),
458 SCF_TIMEOUT = (1 << 3),
459 SCF_UADDR2 = (1 << 4),
460 SCF_VAL3 = (1 << 5),
461 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300462 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300463 int cmd = op & FUTEX_CMD_MASK;
464 size_t printed = 0;
465
466 switch (cmd) {
467#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300468 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
469 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
470 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
471 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
472 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
473 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300474 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300475 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
476 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
477 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
478 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
479 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300480 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
481 default: printed = scnprintf(bf, size, "%#x", cmd); break;
482 }
483
484 if (op & FUTEX_PRIVATE_FLAG)
485 printed += scnprintf(bf + printed, size - printed, "|PRIV");
486
487 if (op & FUTEX_CLOCK_REALTIME)
488 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
489
490 return printed;
491}
492
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300493#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
494
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300495static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
496static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300497
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300498static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
499static DEFINE_STRARRAY(itimers);
500
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300501static const char *whences[] = { "SET", "CUR", "END",
502#ifdef SEEK_DATA
503"DATA",
504#endif
505#ifdef SEEK_HOLE
506"HOLE",
507#endif
508};
509static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300510
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300511static const char *fcntl_cmds[] = {
512 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
513 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
514 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
515 "F_GETOWNER_UIDS",
516};
517static DEFINE_STRARRAY(fcntl_cmds);
518
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300519static const char *rlimit_resources[] = {
520 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
521 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
522 "RTTIME",
523};
524static DEFINE_STRARRAY(rlimit_resources);
525
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300526static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
527static DEFINE_STRARRAY(sighow);
528
David Ahern4f8c1b72013-09-22 19:45:00 -0600529static const char *clockid[] = {
530 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
531 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
532};
533static DEFINE_STRARRAY(clockid);
534
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300535static const char *socket_families[] = {
536 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
537 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
538 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
539 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
540 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
541 "ALG", "NFC", "VSOCK",
542};
543static DEFINE_STRARRAY(socket_families);
544
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300545#ifndef SOCK_TYPE_MASK
546#define SOCK_TYPE_MASK 0xf
547#endif
548
549static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
550 struct syscall_arg *arg)
551{
552 size_t printed;
553 int type = arg->val,
554 flags = type & ~SOCK_TYPE_MASK;
555
556 type &= SOCK_TYPE_MASK;
557 /*
558 * Can't use a strarray, MIPS may override for ABI reasons.
559 */
560 switch (type) {
561#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
562 P_SK_TYPE(STREAM);
563 P_SK_TYPE(DGRAM);
564 P_SK_TYPE(RAW);
565 P_SK_TYPE(RDM);
566 P_SK_TYPE(SEQPACKET);
567 P_SK_TYPE(DCCP);
568 P_SK_TYPE(PACKET);
569#undef P_SK_TYPE
570 default:
571 printed = scnprintf(bf, size, "%#x", type);
572 }
573
574#define P_SK_FLAG(n) \
575 if (flags & SOCK_##n) { \
576 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
577 flags &= ~SOCK_##n; \
578 }
579
580 P_SK_FLAG(CLOEXEC);
581 P_SK_FLAG(NONBLOCK);
582#undef P_SK_FLAG
583
584 if (flags)
585 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
586
587 return printed;
588}
589
590#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
591
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300592#ifndef MSG_PROBE
593#define MSG_PROBE 0x10
594#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600595#ifndef MSG_WAITFORONE
596#define MSG_WAITFORONE 0x10000
597#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300598#ifndef MSG_SENDPAGE_NOTLAST
599#define MSG_SENDPAGE_NOTLAST 0x20000
600#endif
601#ifndef MSG_FASTOPEN
602#define MSG_FASTOPEN 0x20000000
603#endif
604
605static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
606 struct syscall_arg *arg)
607{
608 int printed = 0, flags = arg->val;
609
610 if (flags == 0)
611 return scnprintf(bf, size, "NONE");
612#define P_MSG_FLAG(n) \
613 if (flags & MSG_##n) { \
614 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
615 flags &= ~MSG_##n; \
616 }
617
618 P_MSG_FLAG(OOB);
619 P_MSG_FLAG(PEEK);
620 P_MSG_FLAG(DONTROUTE);
621 P_MSG_FLAG(TRYHARD);
622 P_MSG_FLAG(CTRUNC);
623 P_MSG_FLAG(PROBE);
624 P_MSG_FLAG(TRUNC);
625 P_MSG_FLAG(DONTWAIT);
626 P_MSG_FLAG(EOR);
627 P_MSG_FLAG(WAITALL);
628 P_MSG_FLAG(FIN);
629 P_MSG_FLAG(SYN);
630 P_MSG_FLAG(CONFIRM);
631 P_MSG_FLAG(RST);
632 P_MSG_FLAG(ERRQUEUE);
633 P_MSG_FLAG(NOSIGNAL);
634 P_MSG_FLAG(MORE);
635 P_MSG_FLAG(WAITFORONE);
636 P_MSG_FLAG(SENDPAGE_NOTLAST);
637 P_MSG_FLAG(FASTOPEN);
638 P_MSG_FLAG(CMSG_CLOEXEC);
639#undef P_MSG_FLAG
640
641 if (flags)
642 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
643
644 return printed;
645}
646
647#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
648
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300649static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
650 struct syscall_arg *arg)
651{
652 size_t printed = 0;
653 int mode = arg->val;
654
655 if (mode == F_OK) /* 0 */
656 return scnprintf(bf, size, "F");
657#define P_MODE(n) \
658 if (mode & n##_OK) { \
659 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
660 mode &= ~n##_OK; \
661 }
662
663 P_MODE(R);
664 P_MODE(W);
665 P_MODE(X);
666#undef P_MODE
667
668 if (mode)
669 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
670
671 return printed;
672}
673
674#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
675
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300676static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300677 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300678{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300679 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300680
681 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300682 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300683
684 if (flags == 0)
685 return scnprintf(bf, size, "RDONLY");
686#define P_FLAG(n) \
687 if (flags & O_##n) { \
688 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
689 flags &= ~O_##n; \
690 }
691
692 P_FLAG(APPEND);
693 P_FLAG(ASYNC);
694 P_FLAG(CLOEXEC);
695 P_FLAG(CREAT);
696 P_FLAG(DIRECT);
697 P_FLAG(DIRECTORY);
698 P_FLAG(EXCL);
699 P_FLAG(LARGEFILE);
700 P_FLAG(NOATIME);
701 P_FLAG(NOCTTY);
702#ifdef O_NONBLOCK
703 P_FLAG(NONBLOCK);
704#elif O_NDELAY
705 P_FLAG(NDELAY);
706#endif
707#ifdef O_PATH
708 P_FLAG(PATH);
709#endif
710 P_FLAG(RDWR);
711#ifdef O_DSYNC
712 if ((flags & O_SYNC) == O_SYNC)
713 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
714 else {
715 P_FLAG(DSYNC);
716 }
717#else
718 P_FLAG(SYNC);
719#endif
720 P_FLAG(TRUNC);
721 P_FLAG(WRONLY);
722#undef P_FLAG
723
724 if (flags)
725 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
726
727 return printed;
728}
729
730#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
731
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300732static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
733 struct syscall_arg *arg)
734{
735 int printed = 0, flags = arg->val;
736
737 if (flags == 0)
738 return scnprintf(bf, size, "NONE");
739#define P_FLAG(n) \
740 if (flags & EFD_##n) { \
741 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
742 flags &= ~EFD_##n; \
743 }
744
745 P_FLAG(SEMAPHORE);
746 P_FLAG(CLOEXEC);
747 P_FLAG(NONBLOCK);
748#undef P_FLAG
749
750 if (flags)
751 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
752
753 return printed;
754}
755
756#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
757
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300758static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
759 struct syscall_arg *arg)
760{
761 int printed = 0, flags = arg->val;
762
763#define P_FLAG(n) \
764 if (flags & O_##n) { \
765 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
766 flags &= ~O_##n; \
767 }
768
769 P_FLAG(CLOEXEC);
770 P_FLAG(NONBLOCK);
771#undef P_FLAG
772
773 if (flags)
774 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
775
776 return printed;
777}
778
779#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
780
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300781static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
782{
783 int sig = arg->val;
784
785 switch (sig) {
786#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
787 P_SIGNUM(HUP);
788 P_SIGNUM(INT);
789 P_SIGNUM(QUIT);
790 P_SIGNUM(ILL);
791 P_SIGNUM(TRAP);
792 P_SIGNUM(ABRT);
793 P_SIGNUM(BUS);
794 P_SIGNUM(FPE);
795 P_SIGNUM(KILL);
796 P_SIGNUM(USR1);
797 P_SIGNUM(SEGV);
798 P_SIGNUM(USR2);
799 P_SIGNUM(PIPE);
800 P_SIGNUM(ALRM);
801 P_SIGNUM(TERM);
802 P_SIGNUM(STKFLT);
803 P_SIGNUM(CHLD);
804 P_SIGNUM(CONT);
805 P_SIGNUM(STOP);
806 P_SIGNUM(TSTP);
807 P_SIGNUM(TTIN);
808 P_SIGNUM(TTOU);
809 P_SIGNUM(URG);
810 P_SIGNUM(XCPU);
811 P_SIGNUM(XFSZ);
812 P_SIGNUM(VTALRM);
813 P_SIGNUM(PROF);
814 P_SIGNUM(WINCH);
815 P_SIGNUM(IO);
816 P_SIGNUM(PWR);
817 P_SIGNUM(SYS);
818 default: break;
819 }
820
821 return scnprintf(bf, size, "%#x", sig);
822}
823
824#define SCA_SIGNUM syscall_arg__scnprintf_signum
825
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300826#define TCGETS 0x5401
827
828static const char *tioctls[] = {
829 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
830 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
831 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
832 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
833 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
834 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
835 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
836 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
837 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
838 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
839 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
840 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
841 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
842 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
843 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
844};
845
846static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
847
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300848#define STRARRAY(arg, name, array) \
849 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
850 .arg_parm = { [arg] = &strarray__##array, }
851
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300852static struct syscall_fmt {
853 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300854 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300855 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300856 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300857 bool errmsg;
858 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300859 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300860} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300861 { .name = "access", .errmsg = true,
862 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300863 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300864 { .name = "brk", .hexret = true,
865 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600866 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300867 { .name = "close", .errmsg = true,
868 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300869 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300870 { .name = "dup", .errmsg = true,
871 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
872 { .name = "dup2", .errmsg = true,
873 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
874 { .name = "dup3", .errmsg = true,
875 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300876 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300877 { .name = "eventfd2", .errmsg = true,
878 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300879 { .name = "faccessat", .errmsg = true,
880 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
881 { .name = "fadvise64", .errmsg = true,
882 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
883 { .name = "fallocate", .errmsg = true,
884 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
885 { .name = "fchdir", .errmsg = true,
886 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
887 { .name = "fchmod", .errmsg = true,
888 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
889 { .name = "fchmodat", .errmsg = true,
890 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
891 { .name = "fchown", .errmsg = true,
892 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
893 { .name = "fchownat", .errmsg = true,
894 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
895 { .name = "fcntl", .errmsg = true,
896 .arg_scnprintf = { [0] = SCA_FD, /* fd */
897 [1] = SCA_STRARRAY, /* cmd */ },
898 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
899 { .name = "fdatasync", .errmsg = true,
900 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300901 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300902 .arg_scnprintf = { [0] = SCA_FD, /* fd */
903 [1] = SCA_FLOCK, /* cmd */ }, },
904 { .name = "fsetxattr", .errmsg = true,
905 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
906 { .name = "fstat", .errmsg = true, .alias = "newfstat",
907 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
908 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
909 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
910 { .name = "fstatfs", .errmsg = true,
911 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
912 { .name = "fsync", .errmsg = true,
913 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
914 { .name = "ftruncate", .errmsg = true,
915 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300916 { .name = "futex", .errmsg = true,
917 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300918 { .name = "futimesat", .errmsg = true,
919 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
920 { .name = "getdents", .errmsg = true,
921 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
922 { .name = "getdents64", .errmsg = true,
923 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300924 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
925 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300926 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300927 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300928 [1] = SCA_STRHEXARRAY, /* cmd */
929 [2] = SCA_HEX, /* arg */ },
930 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300931 { .name = "kill", .errmsg = true,
932 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300933 { .name = "linkat", .errmsg = true,
934 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
935 { .name = "lseek", .errmsg = true,
936 .arg_scnprintf = { [0] = SCA_FD, /* fd */
937 [2] = SCA_STRARRAY, /* whence */ },
938 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300939 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300940 { .name = "madvise", .errmsg = true,
941 .arg_scnprintf = { [0] = SCA_HEX, /* start */
942 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300943 { .name = "mkdirat", .errmsg = true,
944 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
945 { .name = "mknodat", .errmsg = true,
946 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300947 { .name = "mlock", .errmsg = true,
948 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
949 { .name = "mlockall", .errmsg = true,
950 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300951 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300952 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300953 [2] = SCA_MMAP_PROT, /* prot */
954 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300955 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300956 .arg_scnprintf = { [0] = SCA_HEX, /* start */
957 [2] = SCA_MMAP_PROT, /* prot */ }, },
958 { .name = "mremap", .hexret = true,
959 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
960 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300961 { .name = "munlock", .errmsg = true,
962 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300963 { .name = "munmap", .errmsg = true,
964 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300965 { .name = "name_to_handle_at", .errmsg = true,
966 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
967 { .name = "newfstatat", .errmsg = true,
968 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300969 { .name = "open", .errmsg = true,
970 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300971 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300972 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
973 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300974 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300975 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
976 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300977 { .name = "pipe2", .errmsg = true,
978 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300979 { .name = "poll", .errmsg = true, .timeout = true, },
980 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300981 { .name = "pread", .errmsg = true, .alias = "pread64",
982 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
983 { .name = "preadv", .errmsg = true, .alias = "pread",
984 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300985 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300986 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
987 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
988 { .name = "pwritev", .errmsg = true,
989 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
990 { .name = "read", .errmsg = true,
991 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
992 { .name = "readlinkat", .errmsg = true,
993 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
994 { .name = "readv", .errmsg = true,
995 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300996 { .name = "recvfrom", .errmsg = true,
997 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
998 { .name = "recvmmsg", .errmsg = true,
999 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1000 { .name = "recvmsg", .errmsg = true,
1001 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001002 { .name = "renameat", .errmsg = true,
1003 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001004 { .name = "rt_sigaction", .errmsg = true,
1005 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001006 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001007 { .name = "rt_sigqueueinfo", .errmsg = true,
1008 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1009 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1010 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001011 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001012 { .name = "sendmmsg", .errmsg = true,
1013 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1014 { .name = "sendmsg", .errmsg = true,
1015 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
1016 { .name = "sendto", .errmsg = true,
1017 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001018 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1019 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001020 { .name = "shutdown", .errmsg = true,
1021 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001022 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001023 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1024 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001025 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001026 { .name = "socketpair", .errmsg = true,
1027 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1028 [1] = SCA_SK_TYPE, /* type */ },
1029 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001030 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001031 { .name = "symlinkat", .errmsg = true,
1032 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001033 { .name = "tgkill", .errmsg = true,
1034 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1035 { .name = "tkill", .errmsg = true,
1036 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001037 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001038 { .name = "unlinkat", .errmsg = true,
1039 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1040 { .name = "utimensat", .errmsg = true,
1041 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
1042 { .name = "write", .errmsg = true,
1043 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1044 { .name = "writev", .errmsg = true,
1045 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001046};
1047
1048static int syscall_fmt__cmp(const void *name, const void *fmtp)
1049{
1050 const struct syscall_fmt *fmt = fmtp;
1051 return strcmp(name, fmt->name);
1052}
1053
1054static struct syscall_fmt *syscall_fmt__find(const char *name)
1055{
1056 const int nmemb = ARRAY_SIZE(syscall_fmts);
1057 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1058}
1059
1060struct syscall {
1061 struct event_format *tp_format;
1062 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001063 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001064 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001065 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001066 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001067};
1068
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001069static size_t fprintf_duration(unsigned long t, FILE *fp)
1070{
1071 double duration = (double)t / NSEC_PER_MSEC;
1072 size_t printed = fprintf(fp, "(");
1073
1074 if (duration >= 1.0)
1075 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1076 else if (duration >= 0.01)
1077 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1078 else
1079 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001080 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001081}
1082
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001083struct thread_trace {
1084 u64 entry_time;
1085 u64 exit_time;
1086 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001087 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001088 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001089 double runtime_ms;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001090 struct {
1091 int max;
1092 char **table;
1093 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001094
1095 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001096};
1097
1098static struct thread_trace *thread_trace__new(void)
1099{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001100 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1101
1102 if (ttrace)
1103 ttrace->paths.max = -1;
1104
David Ahernbf2575c2013-10-08 21:26:53 -06001105 ttrace->syscall_stats = intlist__new(NULL);
1106
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001107 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001108}
1109
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001110static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001111{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001112 struct thread_trace *ttrace;
1113
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001114 if (thread == NULL)
1115 goto fail;
1116
1117 if (thread->priv == NULL)
1118 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001119
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001120 if (thread->priv == NULL)
1121 goto fail;
1122
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001123 ttrace = thread->priv;
1124 ++ttrace->nr_events;
1125
1126 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001127fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001128 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001129 "WARNING: not enough memory, dropping samples!\n");
1130 return NULL;
1131}
1132
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001133struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001134 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001135 struct {
1136 int machine;
1137 int open_id;
1138 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001139 struct {
1140 int max;
1141 struct syscall *table;
1142 } syscalls;
1143 struct perf_record_opts opts;
David Ahern8fb598e2013-09-28 13:13:00 -06001144 struct machine *host;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001145 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -06001146 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001147 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001148 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001149 struct strlist *ev_qualifier;
1150 bool not_ev_qualifier;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001151 bool live;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001152 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -06001153 struct intlist *tid_list;
1154 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001155 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001156 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001157 bool summary;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001158 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001159 bool show_tool_stats;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001160 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001161 double runtime_ms;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001162 struct {
1163 u64 vfs_getname, proc_getname;
1164 } stats;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001165};
1166
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001167static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001168{
1169 struct thread_trace *ttrace = thread->priv;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001170
1171 if (fd > ttrace->paths.max) {
1172 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1173
1174 if (npath == NULL)
1175 return -1;
1176
1177 if (ttrace->paths.max != -1) {
1178 memset(npath + ttrace->paths.max + 1, 0,
1179 (fd - ttrace->paths.max) * sizeof(char *));
1180 } else {
1181 memset(npath, 0, (fd + 1) * sizeof(char *));
1182 }
1183
1184 ttrace->paths.table = npath;
1185 ttrace->paths.max = fd;
1186 }
1187
1188 ttrace->paths.table[fd] = strdup(pathname);
1189
1190 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1191}
1192
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001193static int thread__read_fd_path(struct thread *thread, int fd)
1194{
1195 char linkname[PATH_MAX], pathname[PATH_MAX];
1196 struct stat st;
1197 int ret;
1198
1199 if (thread->pid_ == thread->tid) {
1200 scnprintf(linkname, sizeof(linkname),
1201 "/proc/%d/fd/%d", thread->pid_, fd);
1202 } else {
1203 scnprintf(linkname, sizeof(linkname),
1204 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1205 }
1206
1207 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1208 return -1;
1209
1210 ret = readlink(linkname, pathname, sizeof(pathname));
1211
1212 if (ret < 0 || ret > st.st_size)
1213 return -1;
1214
1215 pathname[ret] = '\0';
1216 return trace__set_fd_pathname(thread, fd, pathname);
1217}
1218
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001219static const char *thread__fd_path(struct thread *thread, int fd,
1220 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001221{
1222 struct thread_trace *ttrace = thread->priv;
1223
1224 if (ttrace == NULL)
1225 return NULL;
1226
1227 if (fd < 0)
1228 return NULL;
1229
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001230 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL))
1231 if (!trace->live)
1232 return NULL;
1233 ++trace->stats.proc_getname;
1234 if (thread__read_fd_path(thread, fd)) {
1235 return NULL;
1236 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001237
1238 return ttrace->paths.table[fd];
1239}
1240
1241static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1242 struct syscall_arg *arg)
1243{
1244 int fd = arg->val;
1245 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001246 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001247
1248 if (path)
1249 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1250
1251 return printed;
1252}
1253
1254static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1255 struct syscall_arg *arg)
1256{
1257 int fd = arg->val;
1258 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1259 struct thread_trace *ttrace = arg->thread->priv;
1260
1261 if (ttrace && fd >= 0 && fd <= ttrace->paths.max) {
1262 free(ttrace->paths.table[fd]);
1263 ttrace->paths.table[fd] = NULL;
1264 }
1265
1266 return printed;
1267}
1268
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001269static bool trace__filter_duration(struct trace *trace, double t)
1270{
1271 return t < (trace->duration_filter * NSEC_PER_MSEC);
1272}
1273
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001274static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1275{
1276 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1277
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001278 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001279}
1280
Namhyung Kimf15eb532012-10-05 14:02:16 +09001281static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001282static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001283
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001284static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001285{
1286 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001287 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001288}
1289
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001290static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001291 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001292{
1293 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001294 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001295
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001296 if (trace->multiple_threads) {
1297 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001298 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001299 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001300 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001301
1302 return printed;
1303}
1304
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001305static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001306 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001307{
1308 int ret = 0;
1309
1310 switch (event->header.type) {
1311 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001312 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001313 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001314 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001315 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001316 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001317 break;
1318 }
1319
1320 return ret;
1321}
1322
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001323static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001324 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001325 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001326 struct machine *machine)
1327{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001328 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001329 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001330}
1331
1332static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1333{
1334 int err = symbol__init();
1335
1336 if (err)
1337 return err;
1338
David Ahern8fb598e2013-09-28 13:13:00 -06001339 trace->host = machine__new_host();
1340 if (trace->host == NULL)
1341 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001342
1343 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001344 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001345 trace__tool_process,
David Ahern8fb598e2013-09-28 13:13:00 -06001346 trace->host);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001347 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001348 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
David Ahern8fb598e2013-09-28 13:13:00 -06001349 trace->host);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001350 }
1351
1352 if (err)
1353 symbol__exit();
1354
1355 return err;
1356}
1357
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001358static int syscall__set_arg_fmts(struct syscall *sc)
1359{
1360 struct format_field *field;
1361 int idx = 0;
1362
1363 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1364 if (sc->arg_scnprintf == NULL)
1365 return -1;
1366
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001367 if (sc->fmt)
1368 sc->arg_parm = sc->fmt->arg_parm;
1369
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001370 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001371 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1372 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1373 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001374 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1375 ++idx;
1376 }
1377
1378 return 0;
1379}
1380
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001381static int trace__read_syscall_info(struct trace *trace, int id)
1382{
1383 char tp_name[128];
1384 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001385 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001386
1387 if (name == NULL)
1388 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001389
1390 if (id > trace->syscalls.max) {
1391 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1392
1393 if (nsyscalls == NULL)
1394 return -1;
1395
1396 if (trace->syscalls.max != -1) {
1397 memset(nsyscalls + trace->syscalls.max + 1, 0,
1398 (id - trace->syscalls.max) * sizeof(*sc));
1399 } else {
1400 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1401 }
1402
1403 trace->syscalls.table = nsyscalls;
1404 trace->syscalls.max = id;
1405 }
1406
1407 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001408 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001409
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001410 if (trace->ev_qualifier) {
1411 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1412
1413 if (!(in ^ trace->not_ev_qualifier)) {
1414 sc->filtered = true;
1415 /*
1416 * No need to do read tracepoint information since this will be
1417 * filtered out.
1418 */
1419 return 0;
1420 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001421 }
1422
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001423 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001424
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001425 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
1426 sc->tp_format = event_format__new("syscalls", tp_name);
1427
1428 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1429 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
1430 sc->tp_format = event_format__new("syscalls", tp_name);
1431 }
1432
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001433 if (sc->tp_format == NULL)
1434 return -1;
1435
1436 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001437}
1438
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001439static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001440 unsigned long *args, struct trace *trace,
1441 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001442{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001443 size_t printed = 0;
1444
1445 if (sc->tp_format != NULL) {
1446 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001447 u8 bit = 1;
1448 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001449 .idx = 0,
1450 .mask = 0,
1451 .trace = trace,
1452 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001453 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001454
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001455 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001456 field = field->next, ++arg.idx, bit <<= 1) {
1457 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001458 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001459 /*
1460 * Suppress this argument if its value is zero and
1461 * and we don't have a string associated in an
1462 * strarray for it.
1463 */
1464 if (args[arg.idx] == 0 &&
1465 !(sc->arg_scnprintf &&
1466 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1467 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001468 continue;
1469
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001470 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001471 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001472 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1473 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001474 if (sc->arg_parm)
1475 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001476 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1477 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001478 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001479 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001480 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001481 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001482 }
1483 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001484 int i = 0;
1485
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001486 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001487 printed += scnprintf(bf + printed, size - printed,
1488 "%sarg%d: %ld",
1489 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001490 ++i;
1491 }
1492 }
1493
1494 return printed;
1495}
1496
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001497typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1498 struct perf_sample *sample);
1499
1500static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001501 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001502{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001503
1504 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001505
1506 /*
1507 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1508 * before that, leaving at a higher verbosity level till that is
1509 * explained. Reproduced with plain ftrace with:
1510 *
1511 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1512 * grep "NR -1 " /t/trace_pipe
1513 *
1514 * After generating some load on the machine.
1515 */
1516 if (verbose > 1) {
1517 static u64 n;
1518 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1519 id, perf_evsel__name(evsel), ++n);
1520 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001521 return NULL;
1522 }
1523
1524 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1525 trace__read_syscall_info(trace, id))
1526 goto out_cant_read;
1527
1528 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1529 goto out_cant_read;
1530
1531 return &trace->syscalls.table[id];
1532
1533out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001534 if (verbose) {
1535 fprintf(trace->output, "Problems reading syscall %d", id);
1536 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1537 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1538 fputs(" information\n", trace->output);
1539 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001540 return NULL;
1541}
1542
David Ahernbf2575c2013-10-08 21:26:53 -06001543static void thread__update_stats(struct thread_trace *ttrace,
1544 int id, struct perf_sample *sample)
1545{
1546 struct int_node *inode;
1547 struct stats *stats;
1548 u64 duration = 0;
1549
1550 inode = intlist__findnew(ttrace->syscall_stats, id);
1551 if (inode == NULL)
1552 return;
1553
1554 stats = inode->priv;
1555 if (stats == NULL) {
1556 stats = malloc(sizeof(struct stats));
1557 if (stats == NULL)
1558 return;
1559 init_stats(stats);
1560 inode->priv = stats;
1561 }
1562
1563 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1564 duration = sample->time - ttrace->entry_time;
1565
1566 update_stats(stats, duration);
1567}
1568
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001569static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1570 struct perf_sample *sample)
1571{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001572 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001573 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001574 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001575 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001576 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001577 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001578 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001579
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001580 if (sc == NULL)
1581 return -1;
1582
1583 if (sc->filtered)
1584 return 0;
1585
David Ahern8fb598e2013-09-28 13:13:00 -06001586 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001587 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001588 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001589 return -1;
1590
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001591 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001592 ttrace = thread->priv;
1593
1594 if (ttrace->entry_str == NULL) {
1595 ttrace->entry_str = malloc(1024);
1596 if (!ttrace->entry_str)
1597 return -1;
1598 }
1599
1600 ttrace->entry_time = sample->time;
1601 msg = ttrace->entry_str;
1602 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1603
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001604 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1605 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001606
1607 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001608 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001609 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1610 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001611 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001612 } else
1613 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001614
1615 return 0;
1616}
1617
1618static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1619 struct perf_sample *sample)
1620{
1621 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001622 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001623 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001624 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001625 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001626 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001627
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001628 if (sc == NULL)
1629 return -1;
1630
1631 if (sc->filtered)
1632 return 0;
1633
David Ahern8fb598e2013-09-28 13:13:00 -06001634 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001635 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001636 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001637 return -1;
1638
David Ahernbf2575c2013-10-08 21:26:53 -06001639 if (trace->summary)
1640 thread__update_stats(ttrace, id, sample);
1641
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001642 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001643
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001644 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1645 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1646 trace->last_vfs_getname = NULL;
1647 ++trace->stats.vfs_getname;
1648 }
1649
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001650 ttrace = thread->priv;
1651
1652 ttrace->exit_time = sample->time;
1653
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001654 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001655 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001656 if (trace__filter_duration(trace, duration))
1657 goto out;
1658 } else if (trace->duration_filter)
1659 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001660
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001661 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001662
1663 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001664 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001665 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001666 fprintf(trace->output, " ... [");
1667 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1668 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001669 }
1670
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001671 if (sc->fmt == NULL) {
1672signed_print:
1673 fprintf(trace->output, ") = %d", ret);
1674 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001675 char bf[256];
1676 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1677 *e = audit_errno_to_name(-ret);
1678
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001679 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001680 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001681 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001682 else if (sc->fmt->hexret)
1683 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001684 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001685 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001686
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001687 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001688out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001689 ttrace->entry_pending = false;
1690
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001691 return 0;
1692}
1693
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001694static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1695 struct perf_sample *sample)
1696{
1697 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1698 return 0;
1699}
1700
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001701static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1702 struct perf_sample *sample)
1703{
1704 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1705 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001706 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001707 sample->pid,
1708 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001709 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001710
1711 if (ttrace == NULL)
1712 goto out_dump;
1713
1714 ttrace->runtime_ms += runtime_ms;
1715 trace->runtime_ms += runtime_ms;
1716 return 0;
1717
1718out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001719 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001720 evsel->name,
1721 perf_evsel__strval(evsel, sample, "comm"),
1722 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1723 runtime,
1724 perf_evsel__intval(evsel, sample, "vruntime"));
1725 return 0;
1726}
1727
David Ahernbdc89662013-08-28 22:29:53 -06001728static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1729{
1730 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1731 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1732 return false;
1733
1734 if (trace->pid_list || trace->tid_list)
1735 return true;
1736
1737 return false;
1738}
1739
David Ahern6810fc92013-08-28 22:29:52 -06001740static int trace__process_sample(struct perf_tool *tool,
1741 union perf_event *event __maybe_unused,
1742 struct perf_sample *sample,
1743 struct perf_evsel *evsel,
1744 struct machine *machine __maybe_unused)
1745{
1746 struct trace *trace = container_of(tool, struct trace, tool);
1747 int err = 0;
1748
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001749 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001750
David Ahernbdc89662013-08-28 22:29:53 -06001751 if (skip_sample(trace, sample))
1752 return 0;
1753
David Ahern4bb09192013-09-04 12:37:43 -06001754 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001755 trace->base_time = sample->time;
1756
1757 if (handler)
1758 handler(trace, evsel, sample);
1759
1760 return err;
1761}
1762
1763static bool
1764perf_session__has_tp(struct perf_session *session, const char *name)
1765{
1766 struct perf_evsel *evsel;
1767
1768 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1769
1770 return evsel != NULL;
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
1893 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1894 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[] = {
2009 { "raw_syscalls:sys_enter", trace__sys_enter, },
2010 { "raw_syscalls:sys_exit", trace__sys_exit, },
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002011 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002012 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002013 struct perf_data_file file = {
2014 .path = input_name,
2015 .mode = PERF_DATA_MODE_READ,
2016 };
David Ahern6810fc92013-08-28 22:29:52 -06002017 struct perf_session *session;
2018 int err = -1;
2019
2020 trace->tool.sample = trace__process_sample;
2021 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002022 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002023 trace->tool.comm = perf_event__process_comm;
2024 trace->tool.exit = perf_event__process_exit;
2025 trace->tool.fork = perf_event__process_fork;
2026 trace->tool.attr = perf_event__process_attr;
2027 trace->tool.tracing_data = perf_event__process_tracing_data;
2028 trace->tool.build_id = perf_event__process_build_id;
2029
2030 trace->tool.ordered_samples = true;
2031 trace->tool.ordering_requires_timestamps = true;
2032
2033 /* add tid to output */
2034 trace->multiple_threads = true;
2035
2036 if (symbol__init() < 0)
2037 return -1;
2038
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002039 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002040 if (session == NULL)
2041 return -ENOMEM;
2042
David Ahern8fb598e2013-09-28 13:13:00 -06002043 trace->host = &session->machines.host;
2044
David Ahern6810fc92013-08-28 22:29:52 -06002045 err = perf_session__set_tracepoints_handlers(session, handlers);
2046 if (err)
2047 goto out;
2048
2049 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
2050 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
2051 goto out;
2052 }
2053
2054 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
2055 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
2056 goto out;
2057 }
2058
David Ahernbdc89662013-08-28 22:29:53 -06002059 err = parse_target_str(trace);
2060 if (err != 0)
2061 goto out;
2062
David Ahern6810fc92013-08-28 22:29:52 -06002063 setup_pager();
2064
2065 err = perf_session__process_events(session, &trace->tool);
2066 if (err)
2067 pr_err("Failed to process events, error %d", err);
2068
David Ahernbf2575c2013-10-08 21:26:53 -06002069 else if (trace->summary)
2070 trace__fprintf_thread_summary(trace, trace->output);
2071
David Ahern6810fc92013-08-28 22:29:52 -06002072out:
2073 perf_session__delete(session);
2074
2075 return err;
2076}
2077
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002078static size_t trace__fprintf_threads_header(FILE *fp)
2079{
2080 size_t printed;
2081
David Ahernbf2575c2013-10-08 21:26:53 -06002082 printed = fprintf(fp, "\n _____________________________________________________________________________\n");
2083 printed += fprintf(fp, " __) Summary of events (__\n\n");
2084 printed += fprintf(fp, " [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
2085 printed += fprintf(fp, " syscall count min max avg stddev\n");
2086 printed += fprintf(fp, " msec msec msec %%\n");
2087 printed += fprintf(fp, " _____________________________________________________________________________\n\n");
2088
2089 return printed;
2090}
2091
2092static size_t thread__dump_stats(struct thread_trace *ttrace,
2093 struct trace *trace, FILE *fp)
2094{
2095 struct stats *stats;
2096 size_t printed = 0;
2097 struct syscall *sc;
2098 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2099
2100 if (inode == NULL)
2101 return 0;
2102
2103 printed += fprintf(fp, "\n");
2104
2105 /* each int_node is a syscall */
2106 while (inode) {
2107 stats = inode->priv;
2108 if (stats) {
2109 double min = (double)(stats->min) / NSEC_PER_MSEC;
2110 double max = (double)(stats->max) / NSEC_PER_MSEC;
2111 double avg = avg_stats(stats);
2112 double pct;
2113 u64 n = (u64) stats->n;
2114
2115 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2116 avg /= NSEC_PER_MSEC;
2117
2118 sc = &trace->syscalls.table[inode->i];
2119 printed += fprintf(fp, "%24s %14s : ", "", sc->name);
2120 printed += fprintf(fp, "%5" PRIu64 " %8.3f %8.3f",
2121 n, min, max);
2122 printed += fprintf(fp, " %8.3f %6.2f\n", avg, pct);
2123 }
2124
2125 inode = intlist__next(inode);
2126 }
2127
2128 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002129
2130 return printed;
2131}
2132
David Ahern896cbb52013-09-28 13:12:59 -06002133/* struct used to pass data to per-thread function */
2134struct summary_data {
2135 FILE *fp;
2136 struct trace *trace;
2137 size_t printed;
2138};
2139
2140static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2141{
2142 struct summary_data *data = priv;
2143 FILE *fp = data->fp;
2144 size_t printed = data->printed;
2145 struct trace *trace = data->trace;
2146 struct thread_trace *ttrace = thread->priv;
2147 const char *color;
2148 double ratio;
2149
2150 if (ttrace == NULL)
2151 return 0;
2152
2153 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2154
2155 color = PERF_COLOR_NORMAL;
2156 if (ratio > 50.0)
2157 color = PERF_COLOR_RED;
2158 else if (ratio > 25.0)
2159 color = PERF_COLOR_GREEN;
2160 else if (ratio > 5.0)
2161 color = PERF_COLOR_YELLOW;
2162
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02002163 printed += color_fprintf(fp, color, "%20s", thread__comm_str(thread));
David Ahern896cbb52013-09-28 13:12:59 -06002164 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
2165 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
2166 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002167 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002168
2169 data->printed += printed;
2170
2171 return 0;
2172}
2173
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002174static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2175{
David Ahern896cbb52013-09-28 13:12:59 -06002176 struct summary_data data = {
2177 .fp = fp,
2178 .trace = trace
2179 };
2180 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002181
David Ahern896cbb52013-09-28 13:12:59 -06002182 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002183
David Ahern896cbb52013-09-28 13:12:59 -06002184 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002185}
2186
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002187static int trace__set_duration(const struct option *opt, const char *str,
2188 int unset __maybe_unused)
2189{
2190 struct trace *trace = opt->value;
2191
2192 trace->duration_filter = atof(str);
2193 return 0;
2194}
2195
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002196static int trace__open_output(struct trace *trace, const char *filename)
2197{
2198 struct stat st;
2199
2200 if (!stat(filename, &st) && st.st_size) {
2201 char oldname[PATH_MAX];
2202
2203 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2204 unlink(oldname);
2205 rename(filename, oldname);
2206 }
2207
2208 trace->output = fopen(filename, "w");
2209
2210 return trace->output == NULL ? -errno : 0;
2211}
2212
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002213int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2214{
2215 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002216 "perf trace [<options>] [<command>]",
2217 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002218 "perf trace record [<options>] [<command>]",
2219 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002220 NULL
2221 };
2222 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002223 .audit = {
2224 .machine = audit_detect_machine(),
2225 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2226 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002227 .syscalls = {
2228 . max = -1,
2229 },
2230 .opts = {
2231 .target = {
2232 .uid = UINT_MAX,
2233 .uses_mmap = true,
2234 },
2235 .user_freq = UINT_MAX,
2236 .user_interval = ULLONG_MAX,
2237 .no_delay = true,
2238 .mmap_pages = 1024,
2239 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002240 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002241 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002242 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002243 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002244 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002245 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002246 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2247 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002248 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002249 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
2250 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002251 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002252 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002253 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2254 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002255 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002256 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002257 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002258 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002259 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002260 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002261 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002262 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002263 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2264 "number of mmap data pages",
2265 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002266 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002267 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002268 OPT_CALLBACK(0, "duration", &trace, "float",
2269 "show only events with duration > N.M ms",
2270 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002271 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002272 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002273 OPT_BOOLEAN('T', "time", &trace.full_time,
2274 "Show full timestamp, not time relative to first start"),
David Ahernbf2575c2013-10-08 21:26:53 -06002275 OPT_BOOLEAN(0, "summary", &trace.summary,
2276 "Show syscall summary with statistics"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002277 OPT_END()
2278 };
2279 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002280 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002281
David Ahern5e2485b2013-09-28 13:13:01 -06002282 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
2283 return trace__record(argc-2, &argv[2]);
2284
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002285 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002286
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002287 if (output_name != NULL) {
2288 err = trace__open_output(&trace, output_name);
2289 if (err < 0) {
2290 perror("failed to create output file");
2291 goto out;
2292 }
2293 }
2294
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002295 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002296 const char *s = ev_qualifier_str;
2297
2298 trace.not_ev_qualifier = *s == '!';
2299 if (trace.not_ev_qualifier)
2300 ++s;
2301 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002302 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002303 fputs("Not enough memory to parse event qualifier",
2304 trace.output);
2305 err = -ENOMEM;
2306 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002307 }
2308 }
2309
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002310 err = perf_target__validate(&trace.opts.target);
2311 if (err) {
2312 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002313 fprintf(trace.output, "%s", bf);
2314 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002315 }
2316
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002317 err = perf_target__parse_uid(&trace.opts.target);
2318 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002319 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002320 fprintf(trace.output, "%s", bf);
2321 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002322 }
2323
Namhyung Kimf15eb532012-10-05 14:02:16 +09002324 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002325 trace.opts.target.system_wide = true;
2326
David Ahern6810fc92013-08-28 22:29:52 -06002327 if (input_name)
2328 err = trace__replay(&trace);
2329 else
2330 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002331
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002332out_close:
2333 if (output_name != NULL)
2334 fclose(trace.output);
2335out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002336 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002337}