blob: 2f82dd78b086023f3f836f18baebd299e0f050c8 [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;
David Ahern8fb598e2013-09-28 13:13:00 -06001222 struct machine *host;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001223 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001224 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001225 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001226 struct strlist *ev_qualifier;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001227 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -06001228 struct intlist *tid_list;
1229 struct intlist *pid_list;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001230 double duration_filter;
1231 double runtime_ms;
1232 struct {
1233 u64 vfs_getname,
1234 proc_getname;
1235 } stats;
1236 bool not_ev_qualifier;
1237 bool live;
1238 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001239 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001240 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001241 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001242 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001243 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001244 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001245 bool trace_syscalls;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001246 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001247};
1248
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001249static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001250{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001251 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001252
1253 if (fd > ttrace->paths.max) {
1254 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1255
1256 if (npath == NULL)
1257 return -1;
1258
1259 if (ttrace->paths.max != -1) {
1260 memset(npath + ttrace->paths.max + 1, 0,
1261 (fd - ttrace->paths.max) * sizeof(char *));
1262 } else {
1263 memset(npath, 0, (fd + 1) * sizeof(char *));
1264 }
1265
1266 ttrace->paths.table = npath;
1267 ttrace->paths.max = fd;
1268 }
1269
1270 ttrace->paths.table[fd] = strdup(pathname);
1271
1272 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1273}
1274
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001275static int thread__read_fd_path(struct thread *thread, int fd)
1276{
1277 char linkname[PATH_MAX], pathname[PATH_MAX];
1278 struct stat st;
1279 int ret;
1280
1281 if (thread->pid_ == thread->tid) {
1282 scnprintf(linkname, sizeof(linkname),
1283 "/proc/%d/fd/%d", thread->pid_, fd);
1284 } else {
1285 scnprintf(linkname, sizeof(linkname),
1286 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1287 }
1288
1289 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1290 return -1;
1291
1292 ret = readlink(linkname, pathname, sizeof(pathname));
1293
1294 if (ret < 0 || ret > st.st_size)
1295 return -1;
1296
1297 pathname[ret] = '\0';
1298 return trace__set_fd_pathname(thread, fd, pathname);
1299}
1300
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001301static const char *thread__fd_path(struct thread *thread, int fd,
1302 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001303{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001304 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001305
1306 if (ttrace == NULL)
1307 return NULL;
1308
1309 if (fd < 0)
1310 return NULL;
1311
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001312 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001313 if (!trace->live)
1314 return NULL;
1315 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001316 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001317 return NULL;
1318 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001319
1320 return ttrace->paths.table[fd];
1321}
1322
1323static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1324 struct syscall_arg *arg)
1325{
1326 int fd = arg->val;
1327 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001328 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001329
1330 if (path)
1331 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1332
1333 return printed;
1334}
1335
1336static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1337 struct syscall_arg *arg)
1338{
1339 int fd = arg->val;
1340 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001341 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001342
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001343 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1344 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001345
1346 return printed;
1347}
1348
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001349static bool trace__filter_duration(struct trace *trace, double t)
1350{
1351 return t < (trace->duration_filter * NSEC_PER_MSEC);
1352}
1353
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001354static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1355{
1356 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1357
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001358 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001359}
1360
Namhyung Kimf15eb532012-10-05 14:02:16 +09001361static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001362static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001363
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001364static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001365{
1366 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001367 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001368}
1369
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001370static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001371 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001372{
1373 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001374 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001375
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001376 if (trace->multiple_threads) {
1377 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001378 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001379 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001380 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001381
1382 return printed;
1383}
1384
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001385static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001386 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001387{
1388 int ret = 0;
1389
1390 switch (event->header.type) {
1391 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001392 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001393 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001394 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001395 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001396 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001397 break;
1398 }
1399
1400 return ret;
1401}
1402
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001403static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001404 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001405 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001406 struct machine *machine)
1407{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001408 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001409 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001410}
1411
1412static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1413{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001414 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001415
1416 if (err)
1417 return err;
1418
David Ahern8fb598e2013-09-28 13:13:00 -06001419 trace->host = machine__new_host();
1420 if (trace->host == NULL)
1421 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001422
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001423 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
1424 evlist->threads, trace__tool_process, false);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001425 if (err)
1426 symbol__exit();
1427
1428 return err;
1429}
1430
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001431static int syscall__set_arg_fmts(struct syscall *sc)
1432{
1433 struct format_field *field;
1434 int idx = 0;
1435
1436 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1437 if (sc->arg_scnprintf == NULL)
1438 return -1;
1439
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001440 if (sc->fmt)
1441 sc->arg_parm = sc->fmt->arg_parm;
1442
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001443 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001444 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1445 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1446 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001447 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1448 ++idx;
1449 }
1450
1451 return 0;
1452}
1453
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001454static int trace__read_syscall_info(struct trace *trace, int id)
1455{
1456 char tp_name[128];
1457 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001458 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001459
1460 if (name == NULL)
1461 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001462
1463 if (id > trace->syscalls.max) {
1464 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1465
1466 if (nsyscalls == NULL)
1467 return -1;
1468
1469 if (trace->syscalls.max != -1) {
1470 memset(nsyscalls + trace->syscalls.max + 1, 0,
1471 (id - trace->syscalls.max) * sizeof(*sc));
1472 } else {
1473 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1474 }
1475
1476 trace->syscalls.table = nsyscalls;
1477 trace->syscalls.max = id;
1478 }
1479
1480 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001481 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001482
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001483 if (trace->ev_qualifier) {
1484 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1485
1486 if (!(in ^ trace->not_ev_qualifier)) {
1487 sc->filtered = true;
1488 /*
1489 * No need to do read tracepoint information since this will be
1490 * filtered out.
1491 */
1492 return 0;
1493 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001494 }
1495
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001496 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001497
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001498 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001499 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001500
1501 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1502 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001503 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001504 }
1505
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001506 if (sc->tp_format == NULL)
1507 return -1;
1508
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001509 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1510
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001511 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001512}
1513
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001514static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001515 unsigned long *args, struct trace *trace,
1516 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001517{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001518 size_t printed = 0;
1519
1520 if (sc->tp_format != NULL) {
1521 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001522 u8 bit = 1;
1523 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001524 .idx = 0,
1525 .mask = 0,
1526 .trace = trace,
1527 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001528 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001529
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001530 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001531 field = field->next, ++arg.idx, bit <<= 1) {
1532 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001533 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001534 /*
1535 * Suppress this argument if its value is zero and
1536 * and we don't have a string associated in an
1537 * strarray for it.
1538 */
1539 if (args[arg.idx] == 0 &&
1540 !(sc->arg_scnprintf &&
1541 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1542 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001543 continue;
1544
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001545 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001546 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001547 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1548 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001549 if (sc->arg_parm)
1550 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001551 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1552 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001553 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001554 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001555 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001556 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001557 }
1558 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001559 int i = 0;
1560
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001561 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001562 printed += scnprintf(bf + printed, size - printed,
1563 "%sarg%d: %ld",
1564 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001565 ++i;
1566 }
1567 }
1568
1569 return printed;
1570}
1571
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001572typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001573 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001574 struct perf_sample *sample);
1575
1576static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001577 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001578{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001579
1580 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001581
1582 /*
1583 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1584 * before that, leaving at a higher verbosity level till that is
1585 * explained. Reproduced with plain ftrace with:
1586 *
1587 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1588 * grep "NR -1 " /t/trace_pipe
1589 *
1590 * After generating some load on the machine.
1591 */
1592 if (verbose > 1) {
1593 static u64 n;
1594 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1595 id, perf_evsel__name(evsel), ++n);
1596 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001597 return NULL;
1598 }
1599
1600 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1601 trace__read_syscall_info(trace, id))
1602 goto out_cant_read;
1603
1604 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1605 goto out_cant_read;
1606
1607 return &trace->syscalls.table[id];
1608
1609out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001610 if (verbose) {
1611 fprintf(trace->output, "Problems reading syscall %d", id);
1612 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1613 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1614 fputs(" information\n", trace->output);
1615 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001616 return NULL;
1617}
1618
David Ahernbf2575c2013-10-08 21:26:53 -06001619static void thread__update_stats(struct thread_trace *ttrace,
1620 int id, struct perf_sample *sample)
1621{
1622 struct int_node *inode;
1623 struct stats *stats;
1624 u64 duration = 0;
1625
1626 inode = intlist__findnew(ttrace->syscall_stats, id);
1627 if (inode == NULL)
1628 return;
1629
1630 stats = inode->priv;
1631 if (stats == NULL) {
1632 stats = malloc(sizeof(struct stats));
1633 if (stats == NULL)
1634 return;
1635 init_stats(stats);
1636 inode->priv = stats;
1637 }
1638
1639 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1640 duration = sample->time - ttrace->entry_time;
1641
1642 update_stats(stats, duration);
1643}
1644
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001645static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001646 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001647 struct perf_sample *sample)
1648{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001649 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001650 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001651 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001652 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001653 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001654 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001655 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001656
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001657 if (sc == NULL)
1658 return -1;
1659
1660 if (sc->filtered)
1661 return 0;
1662
David Ahern8fb598e2013-09-28 13:13:00 -06001663 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001664 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001665 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001666 return -1;
1667
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001668 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001669
1670 if (ttrace->entry_str == NULL) {
1671 ttrace->entry_str = malloc(1024);
1672 if (!ttrace->entry_str)
1673 return -1;
1674 }
1675
1676 ttrace->entry_time = sample->time;
1677 msg = ttrace->entry_str;
1678 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1679
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001680 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1681 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001682
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001683 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001684 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001685 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1686 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001687 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001688 } else
1689 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001690
1691 return 0;
1692}
1693
1694static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001695 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001696 struct perf_sample *sample)
1697{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001698 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001699 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001700 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001701 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001702 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001703 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001704
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001705 if (sc == NULL)
1706 return -1;
1707
1708 if (sc->filtered)
1709 return 0;
1710
David Ahern8fb598e2013-09-28 13:13:00 -06001711 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001712 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001713 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001714 return -1;
1715
David Ahernbf2575c2013-10-08 21:26:53 -06001716 if (trace->summary)
1717 thread__update_stats(ttrace, id, sample);
1718
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001719 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001720
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001721 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1722 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1723 trace->last_vfs_getname = NULL;
1724 ++trace->stats.vfs_getname;
1725 }
1726
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001727 ttrace->exit_time = sample->time;
1728
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001729 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001730 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001731 if (trace__filter_duration(trace, duration))
1732 goto out;
1733 } else if (trace->duration_filter)
1734 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001735
David Ahernfd2eaba2013-11-12 09:31:15 -07001736 if (trace->summary_only)
1737 goto out;
1738
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001739 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001740
1741 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001742 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001743 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001744 fprintf(trace->output, " ... [");
1745 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1746 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001747 }
1748
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001749 if (sc->fmt == NULL) {
1750signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001751 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001752 } else if (ret < 0 && sc->fmt->errmsg) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001753 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001754 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1755 *e = audit_errno_to_name(-ret);
1756
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001757 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001758 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001759 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001760 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001761 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001762 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001763 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001764
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001765 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001766out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001767 ttrace->entry_pending = false;
1768
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001769 return 0;
1770}
1771
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001772static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001773 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001774 struct perf_sample *sample)
1775{
1776 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1777 return 0;
1778}
1779
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001780static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001781 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001782 struct perf_sample *sample)
1783{
1784 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1785 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001786 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001787 sample->pid,
1788 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001789 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001790
1791 if (ttrace == NULL)
1792 goto out_dump;
1793
1794 ttrace->runtime_ms += runtime_ms;
1795 trace->runtime_ms += runtime_ms;
1796 return 0;
1797
1798out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001799 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001800 evsel->name,
1801 perf_evsel__strval(evsel, sample, "comm"),
1802 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1803 runtime,
1804 perf_evsel__intval(evsel, sample, "vruntime"));
1805 return 0;
1806}
1807
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001808static void print_location(FILE *f, struct perf_sample *sample,
1809 struct addr_location *al,
1810 bool print_dso, bool print_sym)
1811{
1812
1813 if ((verbose || print_dso) && al->map)
1814 fprintf(f, "%s@", al->map->dso->long_name);
1815
1816 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001817 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001818 al->addr - al->sym->start);
1819 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001820 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001821 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001822 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001823}
1824
1825static int trace__pgfault(struct trace *trace,
1826 struct perf_evsel *evsel,
1827 union perf_event *event,
1828 struct perf_sample *sample)
1829{
1830 struct thread *thread;
1831 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1832 struct addr_location al;
1833 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001834 struct thread_trace *ttrace;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001835
1836 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001837 ttrace = thread__trace(thread, trace->output);
1838 if (ttrace == NULL)
1839 return -1;
1840
1841 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1842 ttrace->pfmaj++;
1843 else
1844 ttrace->pfmin++;
1845
1846 if (trace->summary_only)
1847 return 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001848
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03001849 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001850 sample->ip, &al);
1851
1852 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
1853
1854 fprintf(trace->output, "%sfault [",
1855 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1856 "maj" : "min");
1857
1858 print_location(trace->output, sample, &al, false, true);
1859
1860 fprintf(trace->output, "] => ");
1861
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03001862 thread__find_addr_location(thread, cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001863 sample->addr, &al);
1864
1865 if (!al.map) {
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03001866 thread__find_addr_location(thread, cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001867 MAP__FUNCTION, sample->addr, &al);
1868
1869 if (al.map)
1870 map_type = 'x';
1871 else
1872 map_type = '?';
1873 }
1874
1875 print_location(trace->output, sample, &al, true, false);
1876
1877 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
1878
1879 return 0;
1880}
1881
David Ahernbdc89662013-08-28 22:29:53 -06001882static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1883{
1884 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1885 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1886 return false;
1887
1888 if (trace->pid_list || trace->tid_list)
1889 return true;
1890
1891 return false;
1892}
1893
David Ahern6810fc92013-08-28 22:29:52 -06001894static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001895 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001896 struct perf_sample *sample,
1897 struct perf_evsel *evsel,
1898 struct machine *machine __maybe_unused)
1899{
1900 struct trace *trace = container_of(tool, struct trace, tool);
1901 int err = 0;
1902
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001903 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001904
David Ahernbdc89662013-08-28 22:29:53 -06001905 if (skip_sample(trace, sample))
1906 return 0;
1907
David Ahern4bb09192013-09-04 12:37:43 -06001908 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001909 trace->base_time = sample->time;
1910
David Ahern31605652013-12-04 19:41:41 -07001911 if (handler) {
1912 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001913 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07001914 }
David Ahern6810fc92013-08-28 22:29:52 -06001915
1916 return err;
1917}
1918
David Ahernbdc89662013-08-28 22:29:53 -06001919static int parse_target_str(struct trace *trace)
1920{
1921 if (trace->opts.target.pid) {
1922 trace->pid_list = intlist__new(trace->opts.target.pid);
1923 if (trace->pid_list == NULL) {
1924 pr_err("Error parsing process id string\n");
1925 return -EINVAL;
1926 }
1927 }
1928
1929 if (trace->opts.target.tid) {
1930 trace->tid_list = intlist__new(trace->opts.target.tid);
1931 if (trace->tid_list == NULL) {
1932 pr_err("Error parsing thread id string\n");
1933 return -EINVAL;
1934 }
1935 }
1936
1937 return 0;
1938}
1939
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001940static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06001941{
1942 unsigned int rec_argc, i, j;
1943 const char **rec_argv;
1944 const char * const record_args[] = {
1945 "record",
1946 "-R",
1947 "-m", "1024",
1948 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06001949 };
1950
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001951 const char * const sc_args[] = { "-e", };
1952 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
1953 const char * const majpf_args[] = { "-e", "major-faults" };
1954 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
1955 const char * const minpf_args[] = { "-e", "minor-faults" };
1956 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
1957
David Ahern9aca7f12013-12-04 19:41:39 -07001958 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001959 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
1960 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06001961 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1962
1963 if (rec_argv == NULL)
1964 return -ENOMEM;
1965
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001966 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06001967 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001968 rec_argv[j++] = record_args[i];
1969
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001970 if (trace->trace_syscalls) {
1971 for (i = 0; i < sc_args_nr; i++)
1972 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06001973
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001974 /* event string may be different for older kernels - e.g., RHEL6 */
1975 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
1976 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
1977 else if (is_valid_tracepoint("syscalls:sys_enter"))
1978 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
1979 else {
1980 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
1981 return -1;
1982 }
David Ahern9aca7f12013-12-04 19:41:39 -07001983 }
David Ahern9aca7f12013-12-04 19:41:39 -07001984
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001985 if (trace->trace_pgfaults & TRACE_PFMAJ)
1986 for (i = 0; i < majpf_args_nr; i++)
1987 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06001988
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001989 if (trace->trace_pgfaults & TRACE_PFMIN)
1990 for (i = 0; i < minpf_args_nr; i++)
1991 rec_argv[j++] = minpf_args[i];
1992
1993 for (i = 0; i < (unsigned int)argc; i++)
1994 rec_argv[j++] = argv[i];
1995
1996 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06001997}
1998
David Ahernbf2575c2013-10-08 21:26:53 -06001999static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2000
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002001static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
2002{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002003 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002004 if (evsel == NULL)
2005 return;
2006
2007 if (perf_evsel__field(evsel, "pathname") == NULL) {
2008 perf_evsel__delete(evsel);
2009 return;
2010 }
2011
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002012 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002013 perf_evlist__add(evlist, evsel);
2014}
2015
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002016static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2017 u64 config)
2018{
2019 struct perf_evsel *evsel;
2020 struct perf_event_attr attr = {
2021 .type = PERF_TYPE_SOFTWARE,
2022 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002023 };
2024
2025 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002026 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002027
2028 event_attr_init(&attr);
2029
2030 evsel = perf_evsel__new(&attr);
2031 if (!evsel)
2032 return -ENOMEM;
2033
2034 evsel->handler = trace__pgfault;
2035 perf_evlist__add(evlist, evsel);
2036
2037 return 0;
2038}
2039
Namhyung Kimf15eb532012-10-05 14:02:16 +09002040static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002041{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09002042 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002043 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002044 int err = -1, i;
2045 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002046 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002047 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002048
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002049 trace->live = true;
2050
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002051 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002052 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002053 goto out;
2054 }
2055
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002056 if (trace->trace_syscalls &&
2057 perf_evlist__add_syscall_newtp(evlist, trace__sys_enter,
2058 trace__sys_exit))
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302059 goto out_error_tp;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002060
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002061 if (trace->trace_syscalls)
2062 perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002063
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002064 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002065 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
2066 /*
2067 * FIXME: This one needs better error handling, as by now we
2068 * already checked that debugfs is mounted and that we have access to it,
2069 * so probably the case is that something is busted wrt this specific
2070 * software event, ditto for the next gotos to out_error_tp...
2071 */
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002072 goto out_error_tp;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002073 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002074
2075 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2076 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
2077 goto out_error_tp;
2078
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002079 if (trace->sched &&
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302080 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2081 trace__sched_stat_runtime))
2082 goto out_error_tp;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002083
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002084 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2085 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002086 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002087 goto out_delete_evlist;
2088 }
2089
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002090 err = trace__symbols_init(trace, evlist);
2091 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002092 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002093 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002094 }
2095
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002096 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002097
Namhyung Kimf15eb532012-10-05 14:02:16 +09002098 signal(SIGCHLD, sig_handler);
2099 signal(SIGINT, sig_handler);
2100
2101 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002102 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002103 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002104 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002105 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002106 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002107 }
2108 }
2109
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002110 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002111 if (err < 0)
2112 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002113
Jiri Olsaf8850372013-11-28 17:57:22 +01002114 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002115 if (err < 0)
2116 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002117
2118 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002119
2120 if (forks)
2121 perf_evlist__start_workload(evlist);
2122
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002123 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002124again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002125 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002126
2127 for (i = 0; i < evlist->nr_mmaps; i++) {
2128 union perf_event *event;
2129
2130 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
2131 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002132 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002133 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002134
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002135 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002136
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002137 err = perf_evlist__parse_sample(evlist, event, &sample);
2138 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002139 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002140 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002141 }
2142
David Ahern4bb09192013-09-04 12:37:43 -06002143 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002144 trace->base_time = sample.time;
2145
2146 if (type != PERF_RECORD_SAMPLE) {
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02002147 trace__process_event(trace, trace->host, event, &sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002148 continue;
2149 }
2150
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002151 evsel = perf_evlist__id2evsel(evlist, sample.id);
2152 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002153 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002154 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002155 }
2156
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002157 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2158 sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002159 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 -03002160 perf_evsel__name(evsel), sample.tid,
2161 sample.cpu, sample.raw_size);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002162 goto next_event;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002163 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002164
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002165 handler = evsel->handler;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002166 handler(trace, evsel, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002167next_event:
2168 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002169
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002170 if (interrupted)
2171 goto out_disable;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002172 }
2173 }
2174
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002175 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002176 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002177
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002178 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2179 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2180 draining = true;
2181
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002182 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002183 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002184 } else {
2185 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002186 }
2187
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002188out_disable:
2189 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002190
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002191 if (!err) {
2192 if (trace->summary)
2193 trace__fprintf_thread_summary(trace, trace->output);
2194
2195 if (trace->show_tool_stats) {
2196 fprintf(trace->output, "Stats:\n "
2197 " vfs_getname : %" PRIu64 "\n"
2198 " proc_getname: %" PRIu64 "\n",
2199 trace->stats.vfs_getname,
2200 trace->stats.proc_getname);
2201 }
2202 }
David Ahernbf2575c2013-10-08 21:26:53 -06002203
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002204out_delete_evlist:
2205 perf_evlist__delete(evlist);
2206out:
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002207 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002208 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002209{
2210 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002211
2212out_error_tp:
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002213 debugfs__strerror_open(errno, errbuf, sizeof(errbuf));
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002214 goto out_error;
2215
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002216out_error_mmap:
2217 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2218 goto out_error;
2219
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002220out_error_open:
2221 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2222
2223out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002224 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302225 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002226}
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002227}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002228
David Ahern6810fc92013-08-28 22:29:52 -06002229static int trace__replay(struct trace *trace)
2230{
2231 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002232 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002233 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002234 struct perf_data_file file = {
2235 .path = input_name,
2236 .mode = PERF_DATA_MODE_READ,
2237 };
David Ahern6810fc92013-08-28 22:29:52 -06002238 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002239 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002240 int err = -1;
2241
2242 trace->tool.sample = trace__process_sample;
2243 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002244 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002245 trace->tool.comm = perf_event__process_comm;
2246 trace->tool.exit = perf_event__process_exit;
2247 trace->tool.fork = perf_event__process_fork;
2248 trace->tool.attr = perf_event__process_attr;
2249 trace->tool.tracing_data = perf_event__process_tracing_data;
2250 trace->tool.build_id = perf_event__process_build_id;
2251
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002252 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002253 trace->tool.ordering_requires_timestamps = true;
2254
2255 /* add tid to output */
2256 trace->multiple_threads = true;
2257
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002258 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002259 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002260 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002261
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002262 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002263 goto out;
2264
David Ahern8fb598e2013-09-28 13:13:00 -06002265 trace->host = &session->machines.host;
2266
David Ahern6810fc92013-08-28 22:29:52 -06002267 err = perf_session__set_tracepoints_handlers(session, handlers);
2268 if (err)
2269 goto out;
2270
Namhyung Kim003824e2013-11-12 15:25:00 +09002271 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2272 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002273 /* older kernels have syscalls tp versus raw_syscalls */
2274 if (evsel == NULL)
2275 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2276 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002277
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002278 if (evsel &&
2279 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2280 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002281 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2282 goto out;
2283 }
2284
2285 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2286 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002287 if (evsel == NULL)
2288 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2289 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002290 if (evsel &&
2291 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2292 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002293 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002294 goto out;
2295 }
2296
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002297 evlist__for_each(session->evlist, evsel) {
2298 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2299 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2300 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2301 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2302 evsel->handler = trace__pgfault;
2303 }
2304
David Ahernbdc89662013-08-28 22:29:53 -06002305 err = parse_target_str(trace);
2306 if (err != 0)
2307 goto out;
2308
David Ahern6810fc92013-08-28 22:29:52 -06002309 setup_pager();
2310
2311 err = perf_session__process_events(session, &trace->tool);
2312 if (err)
2313 pr_err("Failed to process events, error %d", err);
2314
David Ahernbf2575c2013-10-08 21:26:53 -06002315 else if (trace->summary)
2316 trace__fprintf_thread_summary(trace, trace->output);
2317
David Ahern6810fc92013-08-28 22:29:52 -06002318out:
2319 perf_session__delete(session);
2320
2321 return err;
2322}
2323
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002324static size_t trace__fprintf_threads_header(FILE *fp)
2325{
2326 size_t printed;
2327
Pekka Enberg99ff7152013-11-12 16:42:14 +02002328 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002329
2330 return printed;
2331}
2332
2333static size_t thread__dump_stats(struct thread_trace *ttrace,
2334 struct trace *trace, FILE *fp)
2335{
2336 struct stats *stats;
2337 size_t printed = 0;
2338 struct syscall *sc;
2339 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2340
2341 if (inode == NULL)
2342 return 0;
2343
2344 printed += fprintf(fp, "\n");
2345
Pekka Enberg27a778b2013-11-13 14:21:48 +02002346 printed += fprintf(fp, " syscall calls min avg max stddev\n");
2347 printed += fprintf(fp, " (msec) (msec) (msec) (%%)\n");
2348 printed += fprintf(fp, " --------------- -------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002349
David Ahernbf2575c2013-10-08 21:26:53 -06002350 /* each int_node is a syscall */
2351 while (inode) {
2352 stats = inode->priv;
2353 if (stats) {
2354 double min = (double)(stats->min) / NSEC_PER_MSEC;
2355 double max = (double)(stats->max) / NSEC_PER_MSEC;
2356 double avg = avg_stats(stats);
2357 double pct;
2358 u64 n = (u64) stats->n;
2359
2360 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2361 avg /= NSEC_PER_MSEC;
2362
2363 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002364 printed += fprintf(fp, " %-15s", sc->name);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002365 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f",
Pekka Enberg7f7a4132013-11-12 16:10:10 +02002366 n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002367 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002368 }
2369
2370 inode = intlist__next(inode);
2371 }
2372
2373 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002374
2375 return printed;
2376}
2377
David Ahern896cbb52013-09-28 13:12:59 -06002378/* struct used to pass data to per-thread function */
2379struct summary_data {
2380 FILE *fp;
2381 struct trace *trace;
2382 size_t printed;
2383};
2384
2385static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2386{
2387 struct summary_data *data = priv;
2388 FILE *fp = data->fp;
2389 size_t printed = data->printed;
2390 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002391 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002392 double ratio;
2393
2394 if (ttrace == NULL)
2395 return 0;
2396
2397 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2398
Pekka Enberg15e65c62013-11-14 18:43:30 +02002399 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002400 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002401 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002402 if (ttrace->pfmaj)
2403 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2404 if (ttrace->pfmin)
2405 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002406 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002407 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002408
2409 data->printed += printed;
2410
2411 return 0;
2412}
2413
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002414static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2415{
David Ahern896cbb52013-09-28 13:12:59 -06002416 struct summary_data data = {
2417 .fp = fp,
2418 .trace = trace
2419 };
2420 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002421
David Ahern896cbb52013-09-28 13:12:59 -06002422 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002423
David Ahern896cbb52013-09-28 13:12:59 -06002424 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002425}
2426
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002427static int trace__set_duration(const struct option *opt, const char *str,
2428 int unset __maybe_unused)
2429{
2430 struct trace *trace = opt->value;
2431
2432 trace->duration_filter = atof(str);
2433 return 0;
2434}
2435
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002436static int trace__open_output(struct trace *trace, const char *filename)
2437{
2438 struct stat st;
2439
2440 if (!stat(filename, &st) && st.st_size) {
2441 char oldname[PATH_MAX];
2442
2443 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2444 unlink(oldname);
2445 rename(filename, oldname);
2446 }
2447
2448 trace->output = fopen(filename, "w");
2449
2450 return trace->output == NULL ? -errno : 0;
2451}
2452
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002453static int parse_pagefaults(const struct option *opt, const char *str,
2454 int unset __maybe_unused)
2455{
2456 int *trace_pgfaults = opt->value;
2457
2458 if (strcmp(str, "all") == 0)
2459 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2460 else if (strcmp(str, "maj") == 0)
2461 *trace_pgfaults |= TRACE_PFMAJ;
2462 else if (strcmp(str, "min") == 0)
2463 *trace_pgfaults |= TRACE_PFMIN;
2464 else
2465 return -1;
2466
2467 return 0;
2468}
2469
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002470int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2471{
2472 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002473 "perf trace [<options>] [<command>]",
2474 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002475 "perf trace record [<options>] [<command>]",
2476 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002477 NULL
2478 };
2479 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002480 .audit = {
2481 .machine = audit_detect_machine(),
2482 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2483 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002484 .syscalls = {
2485 . max = -1,
2486 },
2487 .opts = {
2488 .target = {
2489 .uid = UINT_MAX,
2490 .uses_mmap = true,
2491 },
2492 .user_freq = UINT_MAX,
2493 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002494 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002495 .mmap_pages = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002496 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002497 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002498 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002499 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002500 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002501 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002502 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002503 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002504 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2505 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002506 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002507 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
2508 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002509 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002510 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002511 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2512 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002513 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002514 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002515 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002516 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002517 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002518 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002519 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002520 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002521 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2522 "number of mmap data pages",
2523 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002524 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002525 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002526 OPT_CALLBACK(0, "duration", &trace, "float",
2527 "show only events with duration > N.M ms",
2528 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002529 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002530 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002531 OPT_BOOLEAN('T', "time", &trace.full_time,
2532 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002533 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2534 "Show only syscall summary with statistics"),
2535 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2536 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002537 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2538 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002539 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002540 OPT_END()
2541 };
2542 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002543 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002544
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002545 argc = parse_options(argc, argv, trace_options, trace_usage,
2546 PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002547
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002548 if (trace.trace_pgfaults) {
2549 trace.opts.sample_address = true;
2550 trace.opts.sample_time = true;
2551 }
2552
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002553 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2554 return trace__record(&trace, argc-1, &argv[1]);
2555
2556 /* summary_only implies summary option, but don't overwrite summary if set */
2557 if (trace.summary_only)
2558 trace.summary = trace.summary_only;
2559
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002560 if (!trace.trace_syscalls && !trace.trace_pgfaults) {
2561 pr_err("Please specify something to trace.\n");
2562 return -1;
2563 }
2564
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002565 if (output_name != NULL) {
2566 err = trace__open_output(&trace, output_name);
2567 if (err < 0) {
2568 perror("failed to create output file");
2569 goto out;
2570 }
2571 }
2572
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002573 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002574 const char *s = ev_qualifier_str;
2575
2576 trace.not_ev_qualifier = *s == '!';
2577 if (trace.not_ev_qualifier)
2578 ++s;
2579 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002580 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002581 fputs("Not enough memory to parse event qualifier",
2582 trace.output);
2583 err = -ENOMEM;
2584 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002585 }
2586 }
2587
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002588 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002589 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002590 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002591 fprintf(trace.output, "%s", bf);
2592 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002593 }
2594
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002595 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002596 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002597 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002598 fprintf(trace.output, "%s", bf);
2599 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002600 }
2601
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002602 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002603 trace.opts.target.system_wide = true;
2604
David Ahern6810fc92013-08-28 22:29:52 -06002605 if (input_name)
2606 err = trace__replay(&trace);
2607 else
2608 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002609
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002610out_close:
2611 if (output_name != NULL)
2612 fclose(trace.output);
2613out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002614 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002615}