blob: a44ac933621917883aebc938655ac2ca45db83b1 [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"
Jiri Olsa97978b32013-12-03 14:09:24 +010014#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070015#include "util/parse-events.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030016
17#include <libaudit.h>
18#include <stdlib.h>
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -030019#include <sys/eventfd.h>
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030020#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030021#include <linux/futex.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030022
Ingo Molnar456857b2013-09-12 15:29:00 +020023/* For older distros: */
24#ifndef MAP_STACK
25# define MAP_STACK 0x20000
26#endif
27
28#ifndef MADV_HWPOISON
29# define MADV_HWPOISON 100
30#endif
31
32#ifndef MADV_MERGEABLE
33# define MADV_MERGEABLE 12
34#endif
35
36#ifndef MADV_UNMERGEABLE
37# define MADV_UNMERGEABLE 13
38#endif
39
Ben Hutchings79d26a62014-02-06 01:00:35 +000040#ifndef EFD_SEMAPHORE
41# define EFD_SEMAPHORE 1
42#endif
43
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -030044struct tp_field {
45 int offset;
46 union {
47 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
48 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
49 };
50};
51
52#define TP_UINT_FIELD(bits) \
53static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
54{ \
55 return *(u##bits *)(sample->raw_data + field->offset); \
56}
57
58TP_UINT_FIELD(8);
59TP_UINT_FIELD(16);
60TP_UINT_FIELD(32);
61TP_UINT_FIELD(64);
62
63#define TP_UINT_FIELD__SWAPPED(bits) \
64static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
65{ \
66 u##bits value = *(u##bits *)(sample->raw_data + field->offset); \
67 return bswap_##bits(value);\
68}
69
70TP_UINT_FIELD__SWAPPED(16);
71TP_UINT_FIELD__SWAPPED(32);
72TP_UINT_FIELD__SWAPPED(64);
73
74static int tp_field__init_uint(struct tp_field *field,
75 struct format_field *format_field,
76 bool needs_swap)
77{
78 field->offset = format_field->offset;
79
80 switch (format_field->size) {
81 case 1:
82 field->integer = tp_field__u8;
83 break;
84 case 2:
85 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
86 break;
87 case 4:
88 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
89 break;
90 case 8:
91 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
92 break;
93 default:
94 return -1;
95 }
96
97 return 0;
98}
99
100static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
101{
102 return sample->raw_data + field->offset;
103}
104
105static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
106{
107 field->offset = format_field->offset;
108 field->pointer = tp_field__ptr;
109 return 0;
110}
111
112struct syscall_tp {
113 struct tp_field id;
114 union {
115 struct tp_field args, ret;
116 };
117};
118
119static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
120 struct tp_field *field,
121 const char *name)
122{
123 struct format_field *format_field = perf_evsel__field(evsel, name);
124
125 if (format_field == NULL)
126 return -1;
127
128 return tp_field__init_uint(field, format_field, evsel->needs_swap);
129}
130
131#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
132 ({ struct syscall_tp *sc = evsel->priv;\
133 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
134
135static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
136 struct tp_field *field,
137 const char *name)
138{
139 struct format_field *format_field = perf_evsel__field(evsel, name);
140
141 if (format_field == NULL)
142 return -1;
143
144 return tp_field__init_ptr(field, format_field);
145}
146
147#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
148 ({ struct syscall_tp *sc = evsel->priv;\
149 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
150
151static void perf_evsel__delete_priv(struct perf_evsel *evsel)
152{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300153 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300154 perf_evsel__delete(evsel);
155}
156
Namhyung Kim96695d42013-11-12 08:51:45 -0300157static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
158{
159 evsel->priv = malloc(sizeof(struct syscall_tp));
160 if (evsel->priv != NULL) {
161 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
162 goto out_delete;
163
164 evsel->handler = handler;
165 return 0;
166 }
167
168 return -ENOMEM;
169
170out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300171 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300172 return -ENOENT;
173}
174
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300175static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300176{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300177 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300178
David Ahern9aca7f12013-12-04 19:41:39 -0700179 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
180 if (evsel == NULL)
181 evsel = perf_evsel__newtp("syscalls", direction);
182
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300183 if (evsel) {
Namhyung Kim96695d42013-11-12 08:51:45 -0300184 if (perf_evsel__init_syscall_tp(evsel, handler))
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300185 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300186 }
187
188 return evsel;
189
190out_delete:
191 perf_evsel__delete_priv(evsel);
192 return NULL;
193}
194
195#define perf_evsel__sc_tp_uint(evsel, name, sample) \
196 ({ struct syscall_tp *fields = evsel->priv; \
197 fields->name.integer(&fields->name, sample); })
198
199#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
200 ({ struct syscall_tp *fields = evsel->priv; \
201 fields->name.pointer(&fields->name, sample); })
202
203static int perf_evlist__add_syscall_newtp(struct perf_evlist *evlist,
204 void *sys_enter_handler,
205 void *sys_exit_handler)
206{
207 int ret = -1;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300208 struct perf_evsel *sys_enter, *sys_exit;
209
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300210 sys_enter = perf_evsel__syscall_newtp("sys_enter", sys_enter_handler);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300211 if (sys_enter == NULL)
212 goto out;
213
214 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
215 goto out_delete_sys_enter;
216
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300217 sys_exit = perf_evsel__syscall_newtp("sys_exit", sys_exit_handler);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300218 if (sys_exit == NULL)
219 goto out_delete_sys_enter;
220
221 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
222 goto out_delete_sys_exit;
223
224 perf_evlist__add(evlist, sys_enter);
225 perf_evlist__add(evlist, sys_exit);
226
227 ret = 0;
228out:
229 return ret;
230
231out_delete_sys_exit:
232 perf_evsel__delete_priv(sys_exit);
233out_delete_sys_enter:
234 perf_evsel__delete_priv(sys_enter);
235 goto out;
236}
237
238
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300239struct syscall_arg {
240 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300241 struct thread *thread;
242 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300243 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300244 u8 idx;
245 u8 mask;
246};
247
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300248struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300249 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300250 int nr_entries;
251 const char **entries;
252};
253
254#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
255 .nr_entries = ARRAY_SIZE(array), \
256 .entries = array, \
257}
258
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300259#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
260 .offset = off, \
261 .nr_entries = ARRAY_SIZE(array), \
262 .entries = array, \
263}
264
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300265static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
266 const char *intfmt,
267 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300268{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300269 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300270 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300271
272 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300273 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300274
275 return scnprintf(bf, size, "%s", sa->entries[idx]);
276}
277
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300278static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
279 struct syscall_arg *arg)
280{
281 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
282}
283
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300284#define SCA_STRARRAY syscall_arg__scnprintf_strarray
285
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300286#if defined(__i386__) || defined(__x86_64__)
287/*
288 * FIXME: Make this available to all arches as soon as the ioctl beautifier
289 * gets rewritten to support all arches.
290 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300291static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
292 struct syscall_arg *arg)
293{
294 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
295}
296
297#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300298#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300299
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300300static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
301 struct syscall_arg *arg);
302
303#define SCA_FD syscall_arg__scnprintf_fd
304
305static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
306 struct syscall_arg *arg)
307{
308 int fd = arg->val;
309
310 if (fd == AT_FDCWD)
311 return scnprintf(bf, size, "CWD");
312
313 return syscall_arg__scnprintf_fd(bf, size, arg);
314}
315
316#define SCA_FDAT syscall_arg__scnprintf_fd_at
317
318static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
319 struct syscall_arg *arg);
320
321#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
322
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300323static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300324 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300325{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300326 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300327}
328
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300329#define SCA_HEX syscall_arg__scnprintf_hex
330
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300331static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300332 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300333{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300334 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300335
336 if (prot == PROT_NONE)
337 return scnprintf(bf, size, "NONE");
338#define P_MMAP_PROT(n) \
339 if (prot & PROT_##n) { \
340 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
341 prot &= ~PROT_##n; \
342 }
343
344 P_MMAP_PROT(EXEC);
345 P_MMAP_PROT(READ);
346 P_MMAP_PROT(WRITE);
347#ifdef PROT_SEM
348 P_MMAP_PROT(SEM);
349#endif
350 P_MMAP_PROT(GROWSDOWN);
351 P_MMAP_PROT(GROWSUP);
352#undef P_MMAP_PROT
353
354 if (prot)
355 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
356
357 return printed;
358}
359
360#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
361
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300362static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300363 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300364{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300365 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300366
367#define P_MMAP_FLAG(n) \
368 if (flags & MAP_##n) { \
369 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
370 flags &= ~MAP_##n; \
371 }
372
373 P_MMAP_FLAG(SHARED);
374 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400375#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300376 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400377#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300378 P_MMAP_FLAG(ANONYMOUS);
379 P_MMAP_FLAG(DENYWRITE);
380 P_MMAP_FLAG(EXECUTABLE);
381 P_MMAP_FLAG(FILE);
382 P_MMAP_FLAG(FIXED);
383 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600384#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300385 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600386#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300387 P_MMAP_FLAG(LOCKED);
388 P_MMAP_FLAG(NONBLOCK);
389 P_MMAP_FLAG(NORESERVE);
390 P_MMAP_FLAG(POPULATE);
391 P_MMAP_FLAG(STACK);
392#ifdef MAP_UNINITIALIZED
393 P_MMAP_FLAG(UNINITIALIZED);
394#endif
395#undef P_MMAP_FLAG
396
397 if (flags)
398 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
399
400 return printed;
401}
402
403#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
404
Alex Snast86998dd2014-08-13 18:42:40 +0300405static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
406 struct syscall_arg *arg)
407{
408 int printed = 0, flags = arg->val;
409
410#define P_MREMAP_FLAG(n) \
411 if (flags & MREMAP_##n) { \
412 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
413 flags &= ~MREMAP_##n; \
414 }
415
416 P_MREMAP_FLAG(MAYMOVE);
417#ifdef MREMAP_FIXED
418 P_MREMAP_FLAG(FIXED);
419#endif
420#undef P_MREMAP_FLAG
421
422 if (flags)
423 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
424
425 return printed;
426}
427
428#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
429
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300430static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300431 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300432{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300433 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300434
435 switch (behavior) {
436#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
437 P_MADV_BHV(NORMAL);
438 P_MADV_BHV(RANDOM);
439 P_MADV_BHV(SEQUENTIAL);
440 P_MADV_BHV(WILLNEED);
441 P_MADV_BHV(DONTNEED);
442 P_MADV_BHV(REMOVE);
443 P_MADV_BHV(DONTFORK);
444 P_MADV_BHV(DOFORK);
445 P_MADV_BHV(HWPOISON);
446#ifdef MADV_SOFT_OFFLINE
447 P_MADV_BHV(SOFT_OFFLINE);
448#endif
449 P_MADV_BHV(MERGEABLE);
450 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600451#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300452 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600453#endif
454#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300455 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600456#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300457#ifdef MADV_DONTDUMP
458 P_MADV_BHV(DONTDUMP);
459#endif
460#ifdef MADV_DODUMP
461 P_MADV_BHV(DODUMP);
462#endif
463#undef P_MADV_PHV
464 default: break;
465 }
466
467 return scnprintf(bf, size, "%#x", behavior);
468}
469
470#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
471
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300472static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
473 struct syscall_arg *arg)
474{
475 int printed = 0, op = arg->val;
476
477 if (op == 0)
478 return scnprintf(bf, size, "NONE");
479#define P_CMD(cmd) \
480 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
481 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
482 op &= ~LOCK_##cmd; \
483 }
484
485 P_CMD(SH);
486 P_CMD(EX);
487 P_CMD(NB);
488 P_CMD(UN);
489 P_CMD(MAND);
490 P_CMD(RW);
491 P_CMD(READ);
492 P_CMD(WRITE);
493#undef P_OP
494
495 if (op)
496 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
497
498 return printed;
499}
500
501#define SCA_FLOCK syscall_arg__scnprintf_flock
502
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300503static 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 -0300504{
505 enum syscall_futex_args {
506 SCF_UADDR = (1 << 0),
507 SCF_OP = (1 << 1),
508 SCF_VAL = (1 << 2),
509 SCF_TIMEOUT = (1 << 3),
510 SCF_UADDR2 = (1 << 4),
511 SCF_VAL3 = (1 << 5),
512 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300513 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300514 int cmd = op & FUTEX_CMD_MASK;
515 size_t printed = 0;
516
517 switch (cmd) {
518#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300519 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
520 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
521 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
522 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
523 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
524 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300525 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300526 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
527 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
528 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
529 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
530 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300531 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
532 default: printed = scnprintf(bf, size, "%#x", cmd); break;
533 }
534
535 if (op & FUTEX_PRIVATE_FLAG)
536 printed += scnprintf(bf + printed, size - printed, "|PRIV");
537
538 if (op & FUTEX_CLOCK_REALTIME)
539 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
540
541 return printed;
542}
543
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300544#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
545
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300546static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
547static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300548
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300549static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
550static DEFINE_STRARRAY(itimers);
551
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300552static const char *whences[] = { "SET", "CUR", "END",
553#ifdef SEEK_DATA
554"DATA",
555#endif
556#ifdef SEEK_HOLE
557"HOLE",
558#endif
559};
560static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300561
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300562static const char *fcntl_cmds[] = {
563 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
564 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
565 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
566 "F_GETOWNER_UIDS",
567};
568static DEFINE_STRARRAY(fcntl_cmds);
569
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300570static const char *rlimit_resources[] = {
571 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
572 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
573 "RTTIME",
574};
575static DEFINE_STRARRAY(rlimit_resources);
576
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300577static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
578static DEFINE_STRARRAY(sighow);
579
David Ahern4f8c1b72013-09-22 19:45:00 -0600580static const char *clockid[] = {
581 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
582 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
583};
584static DEFINE_STRARRAY(clockid);
585
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300586static const char *socket_families[] = {
587 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
588 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
589 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
590 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
591 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
592 "ALG", "NFC", "VSOCK",
593};
594static DEFINE_STRARRAY(socket_families);
595
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300596#ifndef SOCK_TYPE_MASK
597#define SOCK_TYPE_MASK 0xf
598#endif
599
600static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
601 struct syscall_arg *arg)
602{
603 size_t printed;
604 int type = arg->val,
605 flags = type & ~SOCK_TYPE_MASK;
606
607 type &= SOCK_TYPE_MASK;
608 /*
609 * Can't use a strarray, MIPS may override for ABI reasons.
610 */
611 switch (type) {
612#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
613 P_SK_TYPE(STREAM);
614 P_SK_TYPE(DGRAM);
615 P_SK_TYPE(RAW);
616 P_SK_TYPE(RDM);
617 P_SK_TYPE(SEQPACKET);
618 P_SK_TYPE(DCCP);
619 P_SK_TYPE(PACKET);
620#undef P_SK_TYPE
621 default:
622 printed = scnprintf(bf, size, "%#x", type);
623 }
624
625#define P_SK_FLAG(n) \
626 if (flags & SOCK_##n) { \
627 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
628 flags &= ~SOCK_##n; \
629 }
630
631 P_SK_FLAG(CLOEXEC);
632 P_SK_FLAG(NONBLOCK);
633#undef P_SK_FLAG
634
635 if (flags)
636 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
637
638 return printed;
639}
640
641#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
642
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300643#ifndef MSG_PROBE
644#define MSG_PROBE 0x10
645#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600646#ifndef MSG_WAITFORONE
647#define MSG_WAITFORONE 0x10000
648#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300649#ifndef MSG_SENDPAGE_NOTLAST
650#define MSG_SENDPAGE_NOTLAST 0x20000
651#endif
652#ifndef MSG_FASTOPEN
653#define MSG_FASTOPEN 0x20000000
654#endif
655
656static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
657 struct syscall_arg *arg)
658{
659 int printed = 0, flags = arg->val;
660
661 if (flags == 0)
662 return scnprintf(bf, size, "NONE");
663#define P_MSG_FLAG(n) \
664 if (flags & MSG_##n) { \
665 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
666 flags &= ~MSG_##n; \
667 }
668
669 P_MSG_FLAG(OOB);
670 P_MSG_FLAG(PEEK);
671 P_MSG_FLAG(DONTROUTE);
672 P_MSG_FLAG(TRYHARD);
673 P_MSG_FLAG(CTRUNC);
674 P_MSG_FLAG(PROBE);
675 P_MSG_FLAG(TRUNC);
676 P_MSG_FLAG(DONTWAIT);
677 P_MSG_FLAG(EOR);
678 P_MSG_FLAG(WAITALL);
679 P_MSG_FLAG(FIN);
680 P_MSG_FLAG(SYN);
681 P_MSG_FLAG(CONFIRM);
682 P_MSG_FLAG(RST);
683 P_MSG_FLAG(ERRQUEUE);
684 P_MSG_FLAG(NOSIGNAL);
685 P_MSG_FLAG(MORE);
686 P_MSG_FLAG(WAITFORONE);
687 P_MSG_FLAG(SENDPAGE_NOTLAST);
688 P_MSG_FLAG(FASTOPEN);
689 P_MSG_FLAG(CMSG_CLOEXEC);
690#undef P_MSG_FLAG
691
692 if (flags)
693 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
694
695 return printed;
696}
697
698#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
699
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300700static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
701 struct syscall_arg *arg)
702{
703 size_t printed = 0;
704 int mode = arg->val;
705
706 if (mode == F_OK) /* 0 */
707 return scnprintf(bf, size, "F");
708#define P_MODE(n) \
709 if (mode & n##_OK) { \
710 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
711 mode &= ~n##_OK; \
712 }
713
714 P_MODE(R);
715 P_MODE(W);
716 P_MODE(X);
717#undef P_MODE
718
719 if (mode)
720 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
721
722 return printed;
723}
724
725#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
726
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300727static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300728 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300729{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300730 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300731
732 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300733 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300734
735 if (flags == 0)
736 return scnprintf(bf, size, "RDONLY");
737#define P_FLAG(n) \
738 if (flags & O_##n) { \
739 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
740 flags &= ~O_##n; \
741 }
742
743 P_FLAG(APPEND);
744 P_FLAG(ASYNC);
745 P_FLAG(CLOEXEC);
746 P_FLAG(CREAT);
747 P_FLAG(DIRECT);
748 P_FLAG(DIRECTORY);
749 P_FLAG(EXCL);
750 P_FLAG(LARGEFILE);
751 P_FLAG(NOATIME);
752 P_FLAG(NOCTTY);
753#ifdef O_NONBLOCK
754 P_FLAG(NONBLOCK);
755#elif O_NDELAY
756 P_FLAG(NDELAY);
757#endif
758#ifdef O_PATH
759 P_FLAG(PATH);
760#endif
761 P_FLAG(RDWR);
762#ifdef O_DSYNC
763 if ((flags & O_SYNC) == O_SYNC)
764 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
765 else {
766 P_FLAG(DSYNC);
767 }
768#else
769 P_FLAG(SYNC);
770#endif
771 P_FLAG(TRUNC);
772 P_FLAG(WRONLY);
773#undef P_FLAG
774
775 if (flags)
776 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
777
778 return printed;
779}
780
781#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
782
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300783static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
784 struct syscall_arg *arg)
785{
786 int printed = 0, flags = arg->val;
787
788 if (flags == 0)
789 return scnprintf(bf, size, "NONE");
790#define P_FLAG(n) \
791 if (flags & EFD_##n) { \
792 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
793 flags &= ~EFD_##n; \
794 }
795
796 P_FLAG(SEMAPHORE);
797 P_FLAG(CLOEXEC);
798 P_FLAG(NONBLOCK);
799#undef P_FLAG
800
801 if (flags)
802 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
803
804 return printed;
805}
806
807#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
808
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300809static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
810 struct syscall_arg *arg)
811{
812 int printed = 0, flags = arg->val;
813
814#define P_FLAG(n) \
815 if (flags & O_##n) { \
816 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
817 flags &= ~O_##n; \
818 }
819
820 P_FLAG(CLOEXEC);
821 P_FLAG(NONBLOCK);
822#undef P_FLAG
823
824 if (flags)
825 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
826
827 return printed;
828}
829
830#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
831
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300832static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
833{
834 int sig = arg->val;
835
836 switch (sig) {
837#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
838 P_SIGNUM(HUP);
839 P_SIGNUM(INT);
840 P_SIGNUM(QUIT);
841 P_SIGNUM(ILL);
842 P_SIGNUM(TRAP);
843 P_SIGNUM(ABRT);
844 P_SIGNUM(BUS);
845 P_SIGNUM(FPE);
846 P_SIGNUM(KILL);
847 P_SIGNUM(USR1);
848 P_SIGNUM(SEGV);
849 P_SIGNUM(USR2);
850 P_SIGNUM(PIPE);
851 P_SIGNUM(ALRM);
852 P_SIGNUM(TERM);
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300853 P_SIGNUM(CHLD);
854 P_SIGNUM(CONT);
855 P_SIGNUM(STOP);
856 P_SIGNUM(TSTP);
857 P_SIGNUM(TTIN);
858 P_SIGNUM(TTOU);
859 P_SIGNUM(URG);
860 P_SIGNUM(XCPU);
861 P_SIGNUM(XFSZ);
862 P_SIGNUM(VTALRM);
863 P_SIGNUM(PROF);
864 P_SIGNUM(WINCH);
865 P_SIGNUM(IO);
866 P_SIGNUM(PWR);
867 P_SIGNUM(SYS);
Ben Hutchings02c5bb42014-02-06 01:00:41 +0000868#ifdef SIGEMT
869 P_SIGNUM(EMT);
870#endif
871#ifdef SIGSTKFLT
872 P_SIGNUM(STKFLT);
873#endif
874#ifdef SIGSWI
875 P_SIGNUM(SWI);
876#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300877 default: break;
878 }
879
880 return scnprintf(bf, size, "%#x", sig);
881}
882
883#define SCA_SIGNUM syscall_arg__scnprintf_signum
884
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300885#if defined(__i386__) || defined(__x86_64__)
886/*
887 * FIXME: Make this available to all arches.
888 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300889#define TCGETS 0x5401
890
891static const char *tioctls[] = {
892 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
893 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
894 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
895 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
896 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
897 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
898 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
899 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
900 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
901 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
902 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
903 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
904 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
905 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
906 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
907};
908
909static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300910#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300911
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300912#define STRARRAY(arg, name, array) \
913 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
914 .arg_parm = { [arg] = &strarray__##array, }
915
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300916static struct syscall_fmt {
917 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300918 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300919 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300920 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300921 bool errmsg;
922 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300923 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300924} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300925 { .name = "access", .errmsg = true,
926 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300927 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300928 { .name = "brk", .hexret = true,
929 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600930 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300931 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300932 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300933 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300934 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300935 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300936 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300937 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300938 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300939 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300940 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300941 { .name = "eventfd2", .errmsg = true,
942 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300943 { .name = "faccessat", .errmsg = true,
944 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
945 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300946 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300947 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300948 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300949 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300950 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300951 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300952 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300953 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300954 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300955 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300956 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300957 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300958 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300959 { .name = "fcntl", .errmsg = true,
960 .arg_scnprintf = { [0] = SCA_FD, /* fd */
961 [1] = SCA_STRARRAY, /* cmd */ },
962 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
963 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300964 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300965 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300966 .arg_scnprintf = { [0] = SCA_FD, /* fd */
967 [1] = SCA_FLOCK, /* cmd */ }, },
968 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300969 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300970 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300971 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300972 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300973 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300974 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300975 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300976 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300977 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300978 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300979 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300980 { .name = "futex", .errmsg = true,
981 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300982 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300983 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300984 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300985 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300986 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300987 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300988 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
989 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300990 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300991 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300992#if defined(__i386__) || defined(__x86_64__)
993/*
994 * FIXME: Make this available to all arches.
995 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300996 [1] = SCA_STRHEXARRAY, /* cmd */
997 [2] = SCA_HEX, /* arg */ },
998 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300999#else
1000 [2] = SCA_HEX, /* arg */ }, },
1001#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001002 { .name = "kill", .errmsg = true,
1003 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001004 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001005 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001006 { .name = "lseek", .errmsg = true,
1007 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1008 [2] = SCA_STRARRAY, /* whence */ },
1009 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001010 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001011 { .name = "madvise", .errmsg = true,
1012 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1013 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001014 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001015 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001016 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001017 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001018 { .name = "mlock", .errmsg = true,
1019 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1020 { .name = "mlockall", .errmsg = true,
1021 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001022 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001023 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001024 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001025 [3] = SCA_MMAP_FLAGS, /* flags */
1026 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001027 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001028 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1029 [2] = SCA_MMAP_PROT, /* prot */ }, },
1030 { .name = "mremap", .hexret = true,
1031 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001032 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001033 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001034 { .name = "munlock", .errmsg = true,
1035 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001036 { .name = "munmap", .errmsg = true,
1037 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001038 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001039 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001040 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001041 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001042 { .name = "open", .errmsg = true,
1043 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001044 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001045 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1046 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001047 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001048 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1049 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001050 { .name = "pipe2", .errmsg = true,
1051 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001052 { .name = "poll", .errmsg = true, .timeout = true, },
1053 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001054 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001055 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001056 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001057 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001058 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001059 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001060 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001061 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001062 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001063 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001064 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001065 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001066 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001067 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001068 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001069 { .name = "recvfrom", .errmsg = true,
1070 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1071 { .name = "recvmmsg", .errmsg = true,
1072 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1073 { .name = "recvmsg", .errmsg = true,
1074 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001075 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001076 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001077 { .name = "rt_sigaction", .errmsg = true,
1078 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001079 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001080 { .name = "rt_sigqueueinfo", .errmsg = true,
1081 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1082 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1083 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001084 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001085 { .name = "sendmmsg", .errmsg = true,
1086 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1087 { .name = "sendmsg", .errmsg = true,
1088 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
1089 { .name = "sendto", .errmsg = true,
1090 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001091 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1092 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001093 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001094 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001095 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001096 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1097 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001098 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001099 { .name = "socketpair", .errmsg = true,
1100 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1101 [1] = SCA_SK_TYPE, /* type */ },
1102 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001103 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001104 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001105 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001106 { .name = "tgkill", .errmsg = true,
1107 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1108 { .name = "tkill", .errmsg = true,
1109 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001110 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001111 { .name = "unlinkat", .errmsg = true,
1112 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1113 { .name = "utimensat", .errmsg = true,
1114 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
1115 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001116 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001117 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001118 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001119};
1120
1121static int syscall_fmt__cmp(const void *name, const void *fmtp)
1122{
1123 const struct syscall_fmt *fmt = fmtp;
1124 return strcmp(name, fmt->name);
1125}
1126
1127static struct syscall_fmt *syscall_fmt__find(const char *name)
1128{
1129 const int nmemb = ARRAY_SIZE(syscall_fmts);
1130 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1131}
1132
1133struct syscall {
1134 struct event_format *tp_format;
1135 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001136 bool filtered;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001137 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001138 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001139 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001140 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001141};
1142
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001143static size_t fprintf_duration(unsigned long t, FILE *fp)
1144{
1145 double duration = (double)t / NSEC_PER_MSEC;
1146 size_t printed = fprintf(fp, "(");
1147
1148 if (duration >= 1.0)
1149 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1150 else if (duration >= 0.01)
1151 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1152 else
1153 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001154 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001155}
1156
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001157struct thread_trace {
1158 u64 entry_time;
1159 u64 exit_time;
1160 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001161 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001162 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001163 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001164 double runtime_ms;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001165 struct {
1166 int max;
1167 char **table;
1168 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001169
1170 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001171};
1172
1173static struct thread_trace *thread_trace__new(void)
1174{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001175 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1176
1177 if (ttrace)
1178 ttrace->paths.max = -1;
1179
David Ahernbf2575c2013-10-08 21:26:53 -06001180 ttrace->syscall_stats = intlist__new(NULL);
1181
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001182 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001183}
1184
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001185static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001186{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001187 struct thread_trace *ttrace;
1188
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001189 if (thread == NULL)
1190 goto fail;
1191
Namhyung Kim89dceb22014-10-06 09:46:03 +09001192 if (thread__priv(thread) == NULL)
1193 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001194
Namhyung Kim89dceb22014-10-06 09:46:03 +09001195 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001196 goto fail;
1197
Namhyung Kim89dceb22014-10-06 09:46:03 +09001198 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001199 ++ttrace->nr_events;
1200
1201 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001202fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001203 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001204 "WARNING: not enough memory, dropping samples!\n");
1205 return NULL;
1206}
1207
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001208#define TRACE_PFMAJ (1 << 0)
1209#define TRACE_PFMIN (1 << 1)
1210
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001211struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001212 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001213 struct {
1214 int machine;
1215 int open_id;
1216 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001217 struct {
1218 int max;
1219 struct syscall *table;
1220 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001221 struct record_opts opts;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001222 struct perf_evlist *evlist;
David Ahern8fb598e2013-09-28 13:13:00 -06001223 struct machine *host;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001224 struct thread *current;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001225 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001226 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001227 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001228 struct strlist *ev_qualifier;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001229 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -06001230 struct intlist *tid_list;
1231 struct intlist *pid_list;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001232 double duration_filter;
1233 double runtime_ms;
1234 struct {
1235 u64 vfs_getname,
1236 proc_getname;
1237 } stats;
1238 bool not_ev_qualifier;
1239 bool live;
1240 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001241 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001242 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001243 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001244 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001245 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001246 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001247 bool trace_syscalls;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001248 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001249};
1250
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001251static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001252{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001253 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001254
1255 if (fd > ttrace->paths.max) {
1256 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1257
1258 if (npath == NULL)
1259 return -1;
1260
1261 if (ttrace->paths.max != -1) {
1262 memset(npath + ttrace->paths.max + 1, 0,
1263 (fd - ttrace->paths.max) * sizeof(char *));
1264 } else {
1265 memset(npath, 0, (fd + 1) * sizeof(char *));
1266 }
1267
1268 ttrace->paths.table = npath;
1269 ttrace->paths.max = fd;
1270 }
1271
1272 ttrace->paths.table[fd] = strdup(pathname);
1273
1274 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1275}
1276
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001277static int thread__read_fd_path(struct thread *thread, int fd)
1278{
1279 char linkname[PATH_MAX], pathname[PATH_MAX];
1280 struct stat st;
1281 int ret;
1282
1283 if (thread->pid_ == thread->tid) {
1284 scnprintf(linkname, sizeof(linkname),
1285 "/proc/%d/fd/%d", thread->pid_, fd);
1286 } else {
1287 scnprintf(linkname, sizeof(linkname),
1288 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1289 }
1290
1291 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1292 return -1;
1293
1294 ret = readlink(linkname, pathname, sizeof(pathname));
1295
1296 if (ret < 0 || ret > st.st_size)
1297 return -1;
1298
1299 pathname[ret] = '\0';
1300 return trace__set_fd_pathname(thread, fd, pathname);
1301}
1302
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001303static const char *thread__fd_path(struct thread *thread, int fd,
1304 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001305{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001306 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001307
1308 if (ttrace == NULL)
1309 return NULL;
1310
1311 if (fd < 0)
1312 return NULL;
1313
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001314 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001315 if (!trace->live)
1316 return NULL;
1317 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001318 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001319 return NULL;
1320 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001321
1322 return ttrace->paths.table[fd];
1323}
1324
1325static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1326 struct syscall_arg *arg)
1327{
1328 int fd = arg->val;
1329 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001330 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001331
1332 if (path)
1333 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1334
1335 return printed;
1336}
1337
1338static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1339 struct syscall_arg *arg)
1340{
1341 int fd = arg->val;
1342 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001343 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001344
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001345 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1346 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001347
1348 return printed;
1349}
1350
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001351static bool trace__filter_duration(struct trace *trace, double t)
1352{
1353 return t < (trace->duration_filter * NSEC_PER_MSEC);
1354}
1355
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001356static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1357{
1358 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1359
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001360 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001361}
1362
Namhyung Kimf15eb532012-10-05 14:02:16 +09001363static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001364static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001365
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001366static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001367{
1368 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001369 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001370}
1371
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001372static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001373 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001374{
1375 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001376 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001377
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001378 if (trace->multiple_threads) {
1379 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001380 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001381 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001382 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001383
1384 return printed;
1385}
1386
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001387static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001388 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001389{
1390 int ret = 0;
1391
1392 switch (event->header.type) {
1393 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001394 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001395 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001396 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001397 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001398 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001399 break;
1400 }
1401
1402 return ret;
1403}
1404
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001405static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001406 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001407 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001408 struct machine *machine)
1409{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001410 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001411 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001412}
1413
1414static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1415{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001416 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001417
1418 if (err)
1419 return err;
1420
David Ahern8fb598e2013-09-28 13:13:00 -06001421 trace->host = machine__new_host();
1422 if (trace->host == NULL)
1423 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001424
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001425 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
1426 evlist->threads, trace__tool_process, false);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001427 if (err)
1428 symbol__exit();
1429
1430 return err;
1431}
1432
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001433static int syscall__set_arg_fmts(struct syscall *sc)
1434{
1435 struct format_field *field;
1436 int idx = 0;
1437
1438 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1439 if (sc->arg_scnprintf == NULL)
1440 return -1;
1441
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001442 if (sc->fmt)
1443 sc->arg_parm = sc->fmt->arg_parm;
1444
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001445 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001446 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1447 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1448 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001449 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1450 ++idx;
1451 }
1452
1453 return 0;
1454}
1455
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001456static int trace__read_syscall_info(struct trace *trace, int id)
1457{
1458 char tp_name[128];
1459 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001460 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001461
1462 if (name == NULL)
1463 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001464
1465 if (id > trace->syscalls.max) {
1466 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1467
1468 if (nsyscalls == NULL)
1469 return -1;
1470
1471 if (trace->syscalls.max != -1) {
1472 memset(nsyscalls + trace->syscalls.max + 1, 0,
1473 (id - trace->syscalls.max) * sizeof(*sc));
1474 } else {
1475 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1476 }
1477
1478 trace->syscalls.table = nsyscalls;
1479 trace->syscalls.max = id;
1480 }
1481
1482 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001483 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001484
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001485 if (trace->ev_qualifier) {
1486 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1487
1488 if (!(in ^ trace->not_ev_qualifier)) {
1489 sc->filtered = true;
1490 /*
1491 * No need to do read tracepoint information since this will be
1492 * filtered out.
1493 */
1494 return 0;
1495 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001496 }
1497
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001498 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001499
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001500 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001501 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001502
1503 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1504 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001505 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001506 }
1507
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001508 if (sc->tp_format == NULL)
1509 return -1;
1510
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001511 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1512
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001513 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001514}
1515
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001516static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001517 unsigned long *args, struct trace *trace,
1518 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001519{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001520 size_t printed = 0;
1521
1522 if (sc->tp_format != NULL) {
1523 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001524 u8 bit = 1;
1525 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001526 .idx = 0,
1527 .mask = 0,
1528 .trace = trace,
1529 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001530 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001531
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001532 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001533 field = field->next, ++arg.idx, bit <<= 1) {
1534 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001535 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001536 /*
1537 * Suppress this argument if its value is zero and
1538 * and we don't have a string associated in an
1539 * strarray for it.
1540 */
1541 if (args[arg.idx] == 0 &&
1542 !(sc->arg_scnprintf &&
1543 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1544 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001545 continue;
1546
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001547 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001548 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001549 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1550 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001551 if (sc->arg_parm)
1552 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001553 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1554 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001555 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001556 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001557 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001558 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001559 }
1560 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001561 int i = 0;
1562
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001563 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001564 printed += scnprintf(bf + printed, size - printed,
1565 "%sarg%d: %ld",
1566 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001567 ++i;
1568 }
1569 }
1570
1571 return printed;
1572}
1573
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001574typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001575 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001576 struct perf_sample *sample);
1577
1578static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001579 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001580{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001581
1582 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001583
1584 /*
1585 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1586 * before that, leaving at a higher verbosity level till that is
1587 * explained. Reproduced with plain ftrace with:
1588 *
1589 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1590 * grep "NR -1 " /t/trace_pipe
1591 *
1592 * After generating some load on the machine.
1593 */
1594 if (verbose > 1) {
1595 static u64 n;
1596 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1597 id, perf_evsel__name(evsel), ++n);
1598 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001599 return NULL;
1600 }
1601
1602 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1603 trace__read_syscall_info(trace, id))
1604 goto out_cant_read;
1605
1606 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1607 goto out_cant_read;
1608
1609 return &trace->syscalls.table[id];
1610
1611out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001612 if (verbose) {
1613 fprintf(trace->output, "Problems reading syscall %d", id);
1614 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1615 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1616 fputs(" information\n", trace->output);
1617 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001618 return NULL;
1619}
1620
David Ahernbf2575c2013-10-08 21:26:53 -06001621static void thread__update_stats(struct thread_trace *ttrace,
1622 int id, struct perf_sample *sample)
1623{
1624 struct int_node *inode;
1625 struct stats *stats;
1626 u64 duration = 0;
1627
1628 inode = intlist__findnew(ttrace->syscall_stats, id);
1629 if (inode == NULL)
1630 return;
1631
1632 stats = inode->priv;
1633 if (stats == NULL) {
1634 stats = malloc(sizeof(struct stats));
1635 if (stats == NULL)
1636 return;
1637 init_stats(stats);
1638 inode->priv = stats;
1639 }
1640
1641 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1642 duration = sample->time - ttrace->entry_time;
1643
1644 update_stats(stats, duration);
1645}
1646
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001647static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1648{
1649 struct thread_trace *ttrace;
1650 u64 duration;
1651 size_t printed;
1652
1653 if (trace->current == NULL)
1654 return 0;
1655
1656 ttrace = thread__priv(trace->current);
1657
1658 if (!ttrace->entry_pending)
1659 return 0;
1660
1661 duration = sample->time - ttrace->entry_time;
1662
1663 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1664 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1665 ttrace->entry_pending = false;
1666
1667 return printed;
1668}
1669
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001670static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001671 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001672 struct perf_sample *sample)
1673{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001674 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001675 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001676 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001677 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001678 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001679 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001680 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001681
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001682 if (sc == NULL)
1683 return -1;
1684
1685 if (sc->filtered)
1686 return 0;
1687
David Ahern8fb598e2013-09-28 13:13:00 -06001688 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001689 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001690 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001691 return -1;
1692
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001693 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001694
1695 if (ttrace->entry_str == NULL) {
1696 ttrace->entry_str = malloc(1024);
1697 if (!ttrace->entry_str)
1698 return -1;
1699 }
1700
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001701 printed += trace__printf_interrupted_entry(trace, sample);
1702
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001703 ttrace->entry_time = sample->time;
1704 msg = ttrace->entry_str;
1705 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1706
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001707 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1708 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001709
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001710 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001711 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001712 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1713 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001714 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001715 } else
1716 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001717
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001718 trace->current = thread;
1719
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001720 return 0;
1721}
1722
1723static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001724 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001725 struct perf_sample *sample)
1726{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001727 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001728 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001729 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001730 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001731 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001732 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001733
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001734 if (sc == NULL)
1735 return -1;
1736
1737 if (sc->filtered)
1738 return 0;
1739
David Ahern8fb598e2013-09-28 13:13:00 -06001740 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001741 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001742 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001743 return -1;
1744
David Ahernbf2575c2013-10-08 21:26:53 -06001745 if (trace->summary)
1746 thread__update_stats(ttrace, id, sample);
1747
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001748 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001749
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001750 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1751 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1752 trace->last_vfs_getname = NULL;
1753 ++trace->stats.vfs_getname;
1754 }
1755
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001756 ttrace->exit_time = sample->time;
1757
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001758 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001759 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001760 if (trace__filter_duration(trace, duration))
1761 goto out;
1762 } else if (trace->duration_filter)
1763 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001764
David Ahernfd2eaba2013-11-12 09:31:15 -07001765 if (trace->summary_only)
1766 goto out;
1767
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001768 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001769
1770 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001771 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001772 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001773 fprintf(trace->output, " ... [");
1774 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1775 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001776 }
1777
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001778 if (sc->fmt == NULL) {
1779signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001780 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001781 } else if (ret < 0 && sc->fmt->errmsg) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001782 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001783 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1784 *e = audit_errno_to_name(-ret);
1785
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001786 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001787 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001788 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001789 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001790 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001791 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001792 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001793
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001794 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001795out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001796 ttrace->entry_pending = false;
1797
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001798 return 0;
1799}
1800
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001801static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001802 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001803 struct perf_sample *sample)
1804{
1805 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1806 return 0;
1807}
1808
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001809static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001810 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001811 struct perf_sample *sample)
1812{
1813 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1814 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001815 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001816 sample->pid,
1817 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001818 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001819
1820 if (ttrace == NULL)
1821 goto out_dump;
1822
1823 ttrace->runtime_ms += runtime_ms;
1824 trace->runtime_ms += runtime_ms;
1825 return 0;
1826
1827out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001828 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001829 evsel->name,
1830 perf_evsel__strval(evsel, sample, "comm"),
1831 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1832 runtime,
1833 perf_evsel__intval(evsel, sample, "vruntime"));
1834 return 0;
1835}
1836
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001837static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1838 union perf_event *event __maybe_unused,
1839 struct perf_sample *sample)
1840{
1841 trace__printf_interrupted_entry(trace, sample);
1842 trace__fprintf_tstamp(trace, sample->time, trace->output);
1843 fprintf(trace->output, "(%9.9s): %s:", " ", evsel->name);
1844
1845 if (evsel->tp_format) {
1846 event_format__fprintf(evsel->tp_format, sample->cpu,
1847 sample->raw_data, sample->raw_size,
1848 trace->output);
1849 }
1850
1851 fprintf(trace->output, ")\n");
1852 return 0;
1853}
1854
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001855static void print_location(FILE *f, struct perf_sample *sample,
1856 struct addr_location *al,
1857 bool print_dso, bool print_sym)
1858{
1859
1860 if ((verbose || print_dso) && al->map)
1861 fprintf(f, "%s@", al->map->dso->long_name);
1862
1863 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001864 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001865 al->addr - al->sym->start);
1866 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001867 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001868 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001869 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001870}
1871
1872static int trace__pgfault(struct trace *trace,
1873 struct perf_evsel *evsel,
1874 union perf_event *event,
1875 struct perf_sample *sample)
1876{
1877 struct thread *thread;
1878 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1879 struct addr_location al;
1880 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001881 struct thread_trace *ttrace;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001882
1883 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001884 ttrace = thread__trace(thread, trace->output);
1885 if (ttrace == NULL)
1886 return -1;
1887
1888 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1889 ttrace->pfmaj++;
1890 else
1891 ttrace->pfmin++;
1892
1893 if (trace->summary_only)
1894 return 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001895
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03001896 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001897 sample->ip, &al);
1898
1899 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
1900
1901 fprintf(trace->output, "%sfault [",
1902 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1903 "maj" : "min");
1904
1905 print_location(trace->output, sample, &al, false, true);
1906
1907 fprintf(trace->output, "] => ");
1908
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03001909 thread__find_addr_location(thread, cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001910 sample->addr, &al);
1911
1912 if (!al.map) {
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03001913 thread__find_addr_location(thread, cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001914 MAP__FUNCTION, sample->addr, &al);
1915
1916 if (al.map)
1917 map_type = 'x';
1918 else
1919 map_type = '?';
1920 }
1921
1922 print_location(trace->output, sample, &al, true, false);
1923
1924 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
1925
1926 return 0;
1927}
1928
David Ahernbdc89662013-08-28 22:29:53 -06001929static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1930{
1931 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1932 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1933 return false;
1934
1935 if (trace->pid_list || trace->tid_list)
1936 return true;
1937
1938 return false;
1939}
1940
David Ahern6810fc92013-08-28 22:29:52 -06001941static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001942 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001943 struct perf_sample *sample,
1944 struct perf_evsel *evsel,
1945 struct machine *machine __maybe_unused)
1946{
1947 struct trace *trace = container_of(tool, struct trace, tool);
1948 int err = 0;
1949
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001950 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001951
David Ahernbdc89662013-08-28 22:29:53 -06001952 if (skip_sample(trace, sample))
1953 return 0;
1954
David Ahern4bb09192013-09-04 12:37:43 -06001955 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001956 trace->base_time = sample->time;
1957
David Ahern31605652013-12-04 19:41:41 -07001958 if (handler) {
1959 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001960 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07001961 }
David Ahern6810fc92013-08-28 22:29:52 -06001962
1963 return err;
1964}
1965
David Ahernbdc89662013-08-28 22:29:53 -06001966static int parse_target_str(struct trace *trace)
1967{
1968 if (trace->opts.target.pid) {
1969 trace->pid_list = intlist__new(trace->opts.target.pid);
1970 if (trace->pid_list == NULL) {
1971 pr_err("Error parsing process id string\n");
1972 return -EINVAL;
1973 }
1974 }
1975
1976 if (trace->opts.target.tid) {
1977 trace->tid_list = intlist__new(trace->opts.target.tid);
1978 if (trace->tid_list == NULL) {
1979 pr_err("Error parsing thread id string\n");
1980 return -EINVAL;
1981 }
1982 }
1983
1984 return 0;
1985}
1986
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001987static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06001988{
1989 unsigned int rec_argc, i, j;
1990 const char **rec_argv;
1991 const char * const record_args[] = {
1992 "record",
1993 "-R",
1994 "-m", "1024",
1995 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06001996 };
1997
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001998 const char * const sc_args[] = { "-e", };
1999 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2000 const char * const majpf_args[] = { "-e", "major-faults" };
2001 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2002 const char * const minpf_args[] = { "-e", "minor-faults" };
2003 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2004
David Ahern9aca7f12013-12-04 19:41:39 -07002005 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002006 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2007 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002008 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2009
2010 if (rec_argv == NULL)
2011 return -ENOMEM;
2012
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002013 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002014 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002015 rec_argv[j++] = record_args[i];
2016
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002017 if (trace->trace_syscalls) {
2018 for (i = 0; i < sc_args_nr; i++)
2019 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002020
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002021 /* event string may be different for older kernels - e.g., RHEL6 */
2022 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2023 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2024 else if (is_valid_tracepoint("syscalls:sys_enter"))
2025 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2026 else {
2027 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2028 return -1;
2029 }
David Ahern9aca7f12013-12-04 19:41:39 -07002030 }
David Ahern9aca7f12013-12-04 19:41:39 -07002031
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002032 if (trace->trace_pgfaults & TRACE_PFMAJ)
2033 for (i = 0; i < majpf_args_nr; i++)
2034 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002035
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002036 if (trace->trace_pgfaults & TRACE_PFMIN)
2037 for (i = 0; i < minpf_args_nr; i++)
2038 rec_argv[j++] = minpf_args[i];
2039
2040 for (i = 0; i < (unsigned int)argc; i++)
2041 rec_argv[j++] = argv[i];
2042
2043 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002044}
2045
David Ahernbf2575c2013-10-08 21:26:53 -06002046static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2047
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002048static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
2049{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002050 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002051 if (evsel == NULL)
2052 return;
2053
2054 if (perf_evsel__field(evsel, "pathname") == NULL) {
2055 perf_evsel__delete(evsel);
2056 return;
2057 }
2058
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002059 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002060 perf_evlist__add(evlist, evsel);
2061}
2062
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002063static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2064 u64 config)
2065{
2066 struct perf_evsel *evsel;
2067 struct perf_event_attr attr = {
2068 .type = PERF_TYPE_SOFTWARE,
2069 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002070 };
2071
2072 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002073 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002074
2075 event_attr_init(&attr);
2076
2077 evsel = perf_evsel__new(&attr);
2078 if (!evsel)
2079 return -ENOMEM;
2080
2081 evsel->handler = trace__pgfault;
2082 perf_evlist__add(evlist, evsel);
2083
2084 return 0;
2085}
2086
Namhyung Kimf15eb532012-10-05 14:02:16 +09002087static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002088{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002089 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002090 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002091 int err = -1, i;
2092 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002093 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002094 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002095
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002096 trace->live = true;
2097
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002098 if (trace->trace_syscalls &&
2099 perf_evlist__add_syscall_newtp(evlist, trace__sys_enter,
2100 trace__sys_exit))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002101 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002102
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002103 if (trace->trace_syscalls)
2104 perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002105
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002106 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002107 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002108 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002109 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002110
2111 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2112 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002113 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002114
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002115 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002116 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2117 trace__sched_stat_runtime))
2118 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002119
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002120 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2121 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002122 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002123 goto out_delete_evlist;
2124 }
2125
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002126 err = trace__symbols_init(trace, evlist);
2127 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002128 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002129 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002130 }
2131
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002132 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002133
Namhyung Kimf15eb532012-10-05 14:02:16 +09002134 signal(SIGCHLD, sig_handler);
2135 signal(SIGINT, sig_handler);
2136
2137 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002138 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002139 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002140 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002141 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002142 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002143 }
2144 }
2145
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002146 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002147 if (err < 0)
2148 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002149
Jiri Olsaf8850372013-11-28 17:57:22 +01002150 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002151 if (err < 0)
2152 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002153
Namhyung Kimf15eb532012-10-05 14:02:16 +09002154 if (forks)
2155 perf_evlist__start_workload(evlist);
Arnaldo Carvalho de Melof7aa2222015-02-03 13:25:39 -03002156 else
2157 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002158
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002159 trace->multiple_threads = evlist->threads->map[0] == -1 ||
2160 evlist->threads->nr > 1 ||
2161 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002162again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002163 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002164
2165 for (i = 0; i < evlist->nr_mmaps; i++) {
2166 union perf_event *event;
2167
2168 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
2169 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002170 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002171 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002172
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002173 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002174
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002175 err = perf_evlist__parse_sample(evlist, event, &sample);
2176 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002177 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002178 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002179 }
2180
David Ahern4bb09192013-09-04 12:37:43 -06002181 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002182 trace->base_time = sample.time;
2183
2184 if (type != PERF_RECORD_SAMPLE) {
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02002185 trace__process_event(trace, trace->host, event, &sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002186 continue;
2187 }
2188
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002189 evsel = perf_evlist__id2evsel(evlist, sample.id);
2190 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002191 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002192 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002193 }
2194
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002195 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2196 sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002197 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 -03002198 perf_evsel__name(evsel), sample.tid,
2199 sample.cpu, sample.raw_size);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002200 goto next_event;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002201 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002202
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002203 handler = evsel->handler;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002204 handler(trace, evsel, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002205next_event:
2206 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002207
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002208 if (interrupted)
2209 goto out_disable;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002210 }
2211 }
2212
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002213 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002214 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002215
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002216 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2217 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2218 draining = true;
2219
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002220 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002221 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002222 } else {
2223 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002224 }
2225
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002226out_disable:
2227 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002228
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002229 if (!err) {
2230 if (trace->summary)
2231 trace__fprintf_thread_summary(trace, trace->output);
2232
2233 if (trace->show_tool_stats) {
2234 fprintf(trace->output, "Stats:\n "
2235 " vfs_getname : %" PRIu64 "\n"
2236 " proc_getname: %" PRIu64 "\n",
2237 trace->stats.vfs_getname,
2238 trace->stats.proc_getname);
2239 }
2240 }
David Ahernbf2575c2013-10-08 21:26:53 -06002241
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002242out_delete_evlist:
2243 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002244 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002245 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002246 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002247{
2248 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002249
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002250out_error_sched_stat_runtime:
2251 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
2252 goto out_error;
2253
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002254out_error_raw_syscalls:
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002255 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002256 goto out_error;
2257
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002258out_error_mmap:
2259 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2260 goto out_error;
2261
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002262out_error_open:
2263 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2264
2265out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002266 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302267 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002268}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002269out_error_mem:
2270 fprintf(trace->output, "Not enough memory to run!\n");
2271 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002272}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002273
David Ahern6810fc92013-08-28 22:29:52 -06002274static int trace__replay(struct trace *trace)
2275{
2276 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002277 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002278 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002279 struct perf_data_file file = {
2280 .path = input_name,
2281 .mode = PERF_DATA_MODE_READ,
2282 };
David Ahern6810fc92013-08-28 22:29:52 -06002283 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002284 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002285 int err = -1;
2286
2287 trace->tool.sample = trace__process_sample;
2288 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002289 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002290 trace->tool.comm = perf_event__process_comm;
2291 trace->tool.exit = perf_event__process_exit;
2292 trace->tool.fork = perf_event__process_fork;
2293 trace->tool.attr = perf_event__process_attr;
2294 trace->tool.tracing_data = perf_event__process_tracing_data;
2295 trace->tool.build_id = perf_event__process_build_id;
2296
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002297 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002298 trace->tool.ordering_requires_timestamps = true;
2299
2300 /* add tid to output */
2301 trace->multiple_threads = true;
2302
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002303 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002304 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002305 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002306
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002307 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002308 goto out;
2309
David Ahern8fb598e2013-09-28 13:13:00 -06002310 trace->host = &session->machines.host;
2311
David Ahern6810fc92013-08-28 22:29:52 -06002312 err = perf_session__set_tracepoints_handlers(session, handlers);
2313 if (err)
2314 goto out;
2315
Namhyung Kim003824e2013-11-12 15:25:00 +09002316 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2317 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002318 /* older kernels have syscalls tp versus raw_syscalls */
2319 if (evsel == NULL)
2320 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2321 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002322
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002323 if (evsel &&
2324 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2325 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002326 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2327 goto out;
2328 }
2329
2330 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2331 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002332 if (evsel == NULL)
2333 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2334 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002335 if (evsel &&
2336 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2337 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002338 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002339 goto out;
2340 }
2341
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002342 evlist__for_each(session->evlist, evsel) {
2343 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2344 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2345 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2346 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2347 evsel->handler = trace__pgfault;
2348 }
2349
David Ahernbdc89662013-08-28 22:29:53 -06002350 err = parse_target_str(trace);
2351 if (err != 0)
2352 goto out;
2353
David Ahern6810fc92013-08-28 22:29:52 -06002354 setup_pager();
2355
2356 err = perf_session__process_events(session, &trace->tool);
2357 if (err)
2358 pr_err("Failed to process events, error %d", err);
2359
David Ahernbf2575c2013-10-08 21:26:53 -06002360 else if (trace->summary)
2361 trace__fprintf_thread_summary(trace, trace->output);
2362
David Ahern6810fc92013-08-28 22:29:52 -06002363out:
2364 perf_session__delete(session);
2365
2366 return err;
2367}
2368
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002369static size_t trace__fprintf_threads_header(FILE *fp)
2370{
2371 size_t printed;
2372
Pekka Enberg99ff7152013-11-12 16:42:14 +02002373 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002374
2375 return printed;
2376}
2377
2378static size_t thread__dump_stats(struct thread_trace *ttrace,
2379 struct trace *trace, FILE *fp)
2380{
2381 struct stats *stats;
2382 size_t printed = 0;
2383 struct syscall *sc;
2384 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2385
2386 if (inode == NULL)
2387 return 0;
2388
2389 printed += fprintf(fp, "\n");
2390
Pekka Enberg27a778b2013-11-13 14:21:48 +02002391 printed += fprintf(fp, " syscall calls min avg max stddev\n");
2392 printed += fprintf(fp, " (msec) (msec) (msec) (%%)\n");
2393 printed += fprintf(fp, " --------------- -------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002394
David Ahernbf2575c2013-10-08 21:26:53 -06002395 /* each int_node is a syscall */
2396 while (inode) {
2397 stats = inode->priv;
2398 if (stats) {
2399 double min = (double)(stats->min) / NSEC_PER_MSEC;
2400 double max = (double)(stats->max) / NSEC_PER_MSEC;
2401 double avg = avg_stats(stats);
2402 double pct;
2403 u64 n = (u64) stats->n;
2404
2405 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2406 avg /= NSEC_PER_MSEC;
2407
2408 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002409 printed += fprintf(fp, " %-15s", sc->name);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002410 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f",
Pekka Enberg7f7a4132013-11-12 16:10:10 +02002411 n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002412 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002413 }
2414
2415 inode = intlist__next(inode);
2416 }
2417
2418 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002419
2420 return printed;
2421}
2422
David Ahern896cbb52013-09-28 13:12:59 -06002423/* struct used to pass data to per-thread function */
2424struct summary_data {
2425 FILE *fp;
2426 struct trace *trace;
2427 size_t printed;
2428};
2429
2430static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2431{
2432 struct summary_data *data = priv;
2433 FILE *fp = data->fp;
2434 size_t printed = data->printed;
2435 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002436 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002437 double ratio;
2438
2439 if (ttrace == NULL)
2440 return 0;
2441
2442 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2443
Pekka Enberg15e65c62013-11-14 18:43:30 +02002444 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002445 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002446 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002447 if (ttrace->pfmaj)
2448 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2449 if (ttrace->pfmin)
2450 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002451 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002452 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002453
2454 data->printed += printed;
2455
2456 return 0;
2457}
2458
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002459static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2460{
David Ahern896cbb52013-09-28 13:12:59 -06002461 struct summary_data data = {
2462 .fp = fp,
2463 .trace = trace
2464 };
2465 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002466
David Ahern896cbb52013-09-28 13:12:59 -06002467 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002468
David Ahern896cbb52013-09-28 13:12:59 -06002469 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002470}
2471
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002472static int trace__set_duration(const struct option *opt, const char *str,
2473 int unset __maybe_unused)
2474{
2475 struct trace *trace = opt->value;
2476
2477 trace->duration_filter = atof(str);
2478 return 0;
2479}
2480
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002481static int trace__open_output(struct trace *trace, const char *filename)
2482{
2483 struct stat st;
2484
2485 if (!stat(filename, &st) && st.st_size) {
2486 char oldname[PATH_MAX];
2487
2488 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2489 unlink(oldname);
2490 rename(filename, oldname);
2491 }
2492
2493 trace->output = fopen(filename, "w");
2494
2495 return trace->output == NULL ? -errno : 0;
2496}
2497
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002498static int parse_pagefaults(const struct option *opt, const char *str,
2499 int unset __maybe_unused)
2500{
2501 int *trace_pgfaults = opt->value;
2502
2503 if (strcmp(str, "all") == 0)
2504 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2505 else if (strcmp(str, "maj") == 0)
2506 *trace_pgfaults |= TRACE_PFMAJ;
2507 else if (strcmp(str, "min") == 0)
2508 *trace_pgfaults |= TRACE_PFMIN;
2509 else
2510 return -1;
2511
2512 return 0;
2513}
2514
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002515static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2516{
2517 struct perf_evsel *evsel;
2518
2519 evlist__for_each(evlist, evsel)
2520 evsel->handler = handler;
2521}
2522
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002523int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2524{
2525 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002526 "perf trace [<options>] [<command>]",
2527 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002528 "perf trace record [<options>] [<command>]",
2529 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002530 NULL
2531 };
2532 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002533 .audit = {
2534 .machine = audit_detect_machine(),
2535 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2536 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002537 .syscalls = {
2538 . max = -1,
2539 },
2540 .opts = {
2541 .target = {
2542 .uid = UINT_MAX,
2543 .uses_mmap = true,
2544 },
2545 .user_freq = UINT_MAX,
2546 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002547 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002548 .mmap_pages = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002549 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002550 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002551 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002552 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002553 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002554 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002555 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002556 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002557 OPT_CALLBACK(0, "event", &trace.evlist, "event",
2558 "event selector. use 'perf list' to list available events",
2559 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002560 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2561 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002562 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002563 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
2564 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002565 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002566 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002567 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2568 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002569 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002570 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002571 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002572 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002573 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002574 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002575 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002576 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002577 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2578 "number of mmap data pages",
2579 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002580 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002581 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002582 OPT_CALLBACK(0, "duration", &trace, "float",
2583 "show only events with duration > N.M ms",
2584 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002585 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002586 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002587 OPT_BOOLEAN('T', "time", &trace.full_time,
2588 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002589 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2590 "Show only syscall summary with statistics"),
2591 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2592 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002593 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2594 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002595 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002596 OPT_END()
2597 };
2598 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002599 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002600
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002601 trace.evlist = perf_evlist__new();
2602 if (trace.evlist == NULL)
2603 return -ENOMEM;
2604
2605 if (trace.evlist == NULL) {
2606 pr_err("Not enough memory to run!\n");
2607 goto out;
2608 }
2609
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002610 argc = parse_options(argc, argv, trace_options, trace_usage,
2611 PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002612
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002613 if (trace.trace_pgfaults) {
2614 trace.opts.sample_address = true;
2615 trace.opts.sample_time = true;
2616 }
2617
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002618 if (trace.evlist->nr_entries > 0)
2619 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2620
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002621 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2622 return trace__record(&trace, argc-1, &argv[1]);
2623
2624 /* summary_only implies summary option, but don't overwrite summary if set */
2625 if (trace.summary_only)
2626 trace.summary = trace.summary_only;
2627
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002628 if (!trace.trace_syscalls && !trace.trace_pgfaults) {
2629 pr_err("Please specify something to trace.\n");
2630 return -1;
2631 }
2632
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002633 if (output_name != NULL) {
2634 err = trace__open_output(&trace, output_name);
2635 if (err < 0) {
2636 perror("failed to create output file");
2637 goto out;
2638 }
2639 }
2640
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002641 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002642 const char *s = ev_qualifier_str;
2643
2644 trace.not_ev_qualifier = *s == '!';
2645 if (trace.not_ev_qualifier)
2646 ++s;
2647 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002648 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002649 fputs("Not enough memory to parse event qualifier",
2650 trace.output);
2651 err = -ENOMEM;
2652 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002653 }
2654 }
2655
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002656 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002657 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002658 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002659 fprintf(trace.output, "%s", bf);
2660 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002661 }
2662
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002663 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002664 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002665 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002666 fprintf(trace.output, "%s", bf);
2667 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002668 }
2669
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002670 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002671 trace.opts.target.system_wide = true;
2672
David Ahern6810fc92013-08-28 22:29:52 -06002673 if (input_name)
2674 err = trace__replay(&trace);
2675 else
2676 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002677
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002678out_close:
2679 if (output_name != NULL)
2680 fclose(trace.output);
2681out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002682 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002683}