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