blob: 60ccfd52189d3e09f3698964b4545182090d9da8 [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 Melof078c382015-02-21 11:36:52 -08001232 struct {
1233 size_t nr;
1234 pid_t *entries;
1235 } filter_pids;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001236 double duration_filter;
1237 double runtime_ms;
1238 struct {
1239 u64 vfs_getname,
1240 proc_getname;
1241 } stats;
1242 bool not_ev_qualifier;
1243 bool live;
1244 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001245 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001246 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001247 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001248 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001249 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001250 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001251 bool trace_syscalls;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001252 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001253};
1254
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001255static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001256{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001257 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001258
1259 if (fd > ttrace->paths.max) {
1260 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1261
1262 if (npath == NULL)
1263 return -1;
1264
1265 if (ttrace->paths.max != -1) {
1266 memset(npath + ttrace->paths.max + 1, 0,
1267 (fd - ttrace->paths.max) * sizeof(char *));
1268 } else {
1269 memset(npath, 0, (fd + 1) * sizeof(char *));
1270 }
1271
1272 ttrace->paths.table = npath;
1273 ttrace->paths.max = fd;
1274 }
1275
1276 ttrace->paths.table[fd] = strdup(pathname);
1277
1278 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1279}
1280
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001281static int thread__read_fd_path(struct thread *thread, int fd)
1282{
1283 char linkname[PATH_MAX], pathname[PATH_MAX];
1284 struct stat st;
1285 int ret;
1286
1287 if (thread->pid_ == thread->tid) {
1288 scnprintf(linkname, sizeof(linkname),
1289 "/proc/%d/fd/%d", thread->pid_, fd);
1290 } else {
1291 scnprintf(linkname, sizeof(linkname),
1292 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1293 }
1294
1295 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1296 return -1;
1297
1298 ret = readlink(linkname, pathname, sizeof(pathname));
1299
1300 if (ret < 0 || ret > st.st_size)
1301 return -1;
1302
1303 pathname[ret] = '\0';
1304 return trace__set_fd_pathname(thread, fd, pathname);
1305}
1306
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001307static const char *thread__fd_path(struct thread *thread, int fd,
1308 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001309{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001310 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001311
1312 if (ttrace == NULL)
1313 return NULL;
1314
1315 if (fd < 0)
1316 return NULL;
1317
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001318 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001319 if (!trace->live)
1320 return NULL;
1321 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001322 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001323 return NULL;
1324 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001325
1326 return ttrace->paths.table[fd];
1327}
1328
1329static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1330 struct syscall_arg *arg)
1331{
1332 int fd = arg->val;
1333 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001334 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001335
1336 if (path)
1337 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1338
1339 return printed;
1340}
1341
1342static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1343 struct syscall_arg *arg)
1344{
1345 int fd = arg->val;
1346 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001347 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001348
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001349 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1350 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001351
1352 return printed;
1353}
1354
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001355static bool trace__filter_duration(struct trace *trace, double t)
1356{
1357 return t < (trace->duration_filter * NSEC_PER_MSEC);
1358}
1359
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001360static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1361{
1362 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1363
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001364 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001365}
1366
Namhyung Kimf15eb532012-10-05 14:02:16 +09001367static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001368static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001369
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001370static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001371{
1372 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001373 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001374}
1375
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001376static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001377 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001378{
1379 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001380 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001381
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001382 if (trace->multiple_threads) {
1383 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001384 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001385 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001386 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001387
1388 return printed;
1389}
1390
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001391static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001392 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001393{
1394 int ret = 0;
1395
1396 switch (event->header.type) {
1397 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001398 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001399 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001400 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001401 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001402 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001403 break;
1404 }
1405
1406 return ret;
1407}
1408
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001409static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001410 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001411 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001412 struct machine *machine)
1413{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001414 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001415 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001416}
1417
1418static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1419{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001420 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001421
1422 if (err)
1423 return err;
1424
David Ahern8fb598e2013-09-28 13:13:00 -06001425 trace->host = machine__new_host();
1426 if (trace->host == NULL)
1427 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001428
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001429 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
1430 evlist->threads, trace__tool_process, false);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001431 if (err)
1432 symbol__exit();
1433
1434 return err;
1435}
1436
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001437static int syscall__set_arg_fmts(struct syscall *sc)
1438{
1439 struct format_field *field;
1440 int idx = 0;
1441
1442 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1443 if (sc->arg_scnprintf == NULL)
1444 return -1;
1445
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001446 if (sc->fmt)
1447 sc->arg_parm = sc->fmt->arg_parm;
1448
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001449 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001450 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1451 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1452 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001453 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1454 ++idx;
1455 }
1456
1457 return 0;
1458}
1459
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001460static int trace__read_syscall_info(struct trace *trace, int id)
1461{
1462 char tp_name[128];
1463 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001464 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001465
1466 if (name == NULL)
1467 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001468
1469 if (id > trace->syscalls.max) {
1470 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1471
1472 if (nsyscalls == NULL)
1473 return -1;
1474
1475 if (trace->syscalls.max != -1) {
1476 memset(nsyscalls + trace->syscalls.max + 1, 0,
1477 (id - trace->syscalls.max) * sizeof(*sc));
1478 } else {
1479 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1480 }
1481
1482 trace->syscalls.table = nsyscalls;
1483 trace->syscalls.max = id;
1484 }
1485
1486 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001487 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001488
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001489 if (trace->ev_qualifier) {
1490 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1491
1492 if (!(in ^ trace->not_ev_qualifier)) {
1493 sc->filtered = true;
1494 /*
1495 * No need to do read tracepoint information since this will be
1496 * filtered out.
1497 */
1498 return 0;
1499 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001500 }
1501
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001502 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001503
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001504 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
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 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1508 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001509 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001510 }
1511
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001512 if (sc->tp_format == NULL)
1513 return -1;
1514
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001515 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1516
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001517 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001518}
1519
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001520static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001521 unsigned long *args, struct trace *trace,
1522 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001523{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001524 size_t printed = 0;
1525
1526 if (sc->tp_format != NULL) {
1527 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001528 u8 bit = 1;
1529 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001530 .idx = 0,
1531 .mask = 0,
1532 .trace = trace,
1533 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001534 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001535
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001536 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001537 field = field->next, ++arg.idx, bit <<= 1) {
1538 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001539 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001540 /*
1541 * Suppress this argument if its value is zero and
1542 * and we don't have a string associated in an
1543 * strarray for it.
1544 */
1545 if (args[arg.idx] == 0 &&
1546 !(sc->arg_scnprintf &&
1547 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1548 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001549 continue;
1550
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001551 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001552 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001553 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1554 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001555 if (sc->arg_parm)
1556 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001557 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1558 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001559 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001560 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001561 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001562 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001563 }
1564 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001565 int i = 0;
1566
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001567 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001568 printed += scnprintf(bf + printed, size - printed,
1569 "%sarg%d: %ld",
1570 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001571 ++i;
1572 }
1573 }
1574
1575 return printed;
1576}
1577
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001578typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001579 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001580 struct perf_sample *sample);
1581
1582static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001583 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001584{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001585
1586 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001587
1588 /*
1589 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1590 * before that, leaving at a higher verbosity level till that is
1591 * explained. Reproduced with plain ftrace with:
1592 *
1593 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1594 * grep "NR -1 " /t/trace_pipe
1595 *
1596 * After generating some load on the machine.
1597 */
1598 if (verbose > 1) {
1599 static u64 n;
1600 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1601 id, perf_evsel__name(evsel), ++n);
1602 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001603 return NULL;
1604 }
1605
1606 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1607 trace__read_syscall_info(trace, id))
1608 goto out_cant_read;
1609
1610 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1611 goto out_cant_read;
1612
1613 return &trace->syscalls.table[id];
1614
1615out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001616 if (verbose) {
1617 fprintf(trace->output, "Problems reading syscall %d", id);
1618 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1619 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1620 fputs(" information\n", trace->output);
1621 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001622 return NULL;
1623}
1624
David Ahernbf2575c2013-10-08 21:26:53 -06001625static void thread__update_stats(struct thread_trace *ttrace,
1626 int id, struct perf_sample *sample)
1627{
1628 struct int_node *inode;
1629 struct stats *stats;
1630 u64 duration = 0;
1631
1632 inode = intlist__findnew(ttrace->syscall_stats, id);
1633 if (inode == NULL)
1634 return;
1635
1636 stats = inode->priv;
1637 if (stats == NULL) {
1638 stats = malloc(sizeof(struct stats));
1639 if (stats == NULL)
1640 return;
1641 init_stats(stats);
1642 inode->priv = stats;
1643 }
1644
1645 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1646 duration = sample->time - ttrace->entry_time;
1647
1648 update_stats(stats, duration);
1649}
1650
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001651static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1652{
1653 struct thread_trace *ttrace;
1654 u64 duration;
1655 size_t printed;
1656
1657 if (trace->current == NULL)
1658 return 0;
1659
1660 ttrace = thread__priv(trace->current);
1661
1662 if (!ttrace->entry_pending)
1663 return 0;
1664
1665 duration = sample->time - ttrace->entry_time;
1666
1667 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1668 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1669 ttrace->entry_pending = false;
1670
1671 return printed;
1672}
1673
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001674static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001675 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001676 struct perf_sample *sample)
1677{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001678 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001679 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001680 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001681 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001682 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001683 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001684 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001685
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001686 if (sc == NULL)
1687 return -1;
1688
1689 if (sc->filtered)
1690 return 0;
1691
David Ahern8fb598e2013-09-28 13:13:00 -06001692 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001693 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001694 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001695 return -1;
1696
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001697 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001698
1699 if (ttrace->entry_str == NULL) {
1700 ttrace->entry_str = malloc(1024);
1701 if (!ttrace->entry_str)
1702 return -1;
1703 }
1704
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001705 printed += trace__printf_interrupted_entry(trace, sample);
1706
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001707 ttrace->entry_time = sample->time;
1708 msg = ttrace->entry_str;
1709 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1710
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001711 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1712 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001713
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001714 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001715 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001716 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1717 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001718 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001719 } else
1720 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001721
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001722 trace->current = thread;
1723
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001724 return 0;
1725}
1726
1727static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001728 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001729 struct perf_sample *sample)
1730{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001731 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001732 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001733 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001734 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001735 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001736 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001737
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001738 if (sc == NULL)
1739 return -1;
1740
1741 if (sc->filtered)
1742 return 0;
1743
David Ahern8fb598e2013-09-28 13:13:00 -06001744 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001745 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001746 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001747 return -1;
1748
David Ahernbf2575c2013-10-08 21:26:53 -06001749 if (trace->summary)
1750 thread__update_stats(ttrace, id, sample);
1751
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001752 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001753
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001754 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1755 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1756 trace->last_vfs_getname = NULL;
1757 ++trace->stats.vfs_getname;
1758 }
1759
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001760 ttrace->exit_time = sample->time;
1761
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001762 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001763 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001764 if (trace__filter_duration(trace, duration))
1765 goto out;
1766 } else if (trace->duration_filter)
1767 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001768
David Ahernfd2eaba2013-11-12 09:31:15 -07001769 if (trace->summary_only)
1770 goto out;
1771
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001772 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001773
1774 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001775 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001776 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001777 fprintf(trace->output, " ... [");
1778 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1779 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001780 }
1781
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001782 if (sc->fmt == NULL) {
1783signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001784 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001785 } else if (ret < 0 && sc->fmt->errmsg) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001786 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001787 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1788 *e = audit_errno_to_name(-ret);
1789
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001790 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001791 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001792 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001793 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001794 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001795 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001796 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001797
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001798 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001799out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001800 ttrace->entry_pending = false;
1801
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001802 return 0;
1803}
1804
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001805static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001806 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001807 struct perf_sample *sample)
1808{
1809 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1810 return 0;
1811}
1812
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001813static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001814 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001815 struct perf_sample *sample)
1816{
1817 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1818 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001819 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001820 sample->pid,
1821 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001822 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001823
1824 if (ttrace == NULL)
1825 goto out_dump;
1826
1827 ttrace->runtime_ms += runtime_ms;
1828 trace->runtime_ms += runtime_ms;
1829 return 0;
1830
1831out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001832 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001833 evsel->name,
1834 perf_evsel__strval(evsel, sample, "comm"),
1835 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1836 runtime,
1837 perf_evsel__intval(evsel, sample, "vruntime"));
1838 return 0;
1839}
1840
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001841static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1842 union perf_event *event __maybe_unused,
1843 struct perf_sample *sample)
1844{
1845 trace__printf_interrupted_entry(trace, sample);
1846 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001847
1848 if (trace->trace_syscalls)
1849 fprintf(trace->output, "( ): ");
1850
1851 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001852
1853 if (evsel->tp_format) {
1854 event_format__fprintf(evsel->tp_format, sample->cpu,
1855 sample->raw_data, sample->raw_size,
1856 trace->output);
1857 }
1858
1859 fprintf(trace->output, ")\n");
1860 return 0;
1861}
1862
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001863static void print_location(FILE *f, struct perf_sample *sample,
1864 struct addr_location *al,
1865 bool print_dso, bool print_sym)
1866{
1867
1868 if ((verbose || print_dso) && al->map)
1869 fprintf(f, "%s@", al->map->dso->long_name);
1870
1871 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001872 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001873 al->addr - al->sym->start);
1874 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001875 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001876 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001877 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001878}
1879
1880static int trace__pgfault(struct trace *trace,
1881 struct perf_evsel *evsel,
1882 union perf_event *event,
1883 struct perf_sample *sample)
1884{
1885 struct thread *thread;
1886 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1887 struct addr_location al;
1888 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001889 struct thread_trace *ttrace;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001890
1891 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001892 ttrace = thread__trace(thread, trace->output);
1893 if (ttrace == NULL)
1894 return -1;
1895
1896 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1897 ttrace->pfmaj++;
1898 else
1899 ttrace->pfmin++;
1900
1901 if (trace->summary_only)
1902 return 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001903
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03001904 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001905 sample->ip, &al);
1906
1907 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
1908
1909 fprintf(trace->output, "%sfault [",
1910 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1911 "maj" : "min");
1912
1913 print_location(trace->output, sample, &al, false, true);
1914
1915 fprintf(trace->output, "] => ");
1916
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03001917 thread__find_addr_location(thread, cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001918 sample->addr, &al);
1919
1920 if (!al.map) {
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03001921 thread__find_addr_location(thread, cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001922 MAP__FUNCTION, sample->addr, &al);
1923
1924 if (al.map)
1925 map_type = 'x';
1926 else
1927 map_type = '?';
1928 }
1929
1930 print_location(trace->output, sample, &al, true, false);
1931
1932 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
1933
1934 return 0;
1935}
1936
David Ahernbdc89662013-08-28 22:29:53 -06001937static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1938{
1939 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1940 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1941 return false;
1942
1943 if (trace->pid_list || trace->tid_list)
1944 return true;
1945
1946 return false;
1947}
1948
David Ahern6810fc92013-08-28 22:29:52 -06001949static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001950 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001951 struct perf_sample *sample,
1952 struct perf_evsel *evsel,
1953 struct machine *machine __maybe_unused)
1954{
1955 struct trace *trace = container_of(tool, struct trace, tool);
1956 int err = 0;
1957
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001958 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001959
David Ahernbdc89662013-08-28 22:29:53 -06001960 if (skip_sample(trace, sample))
1961 return 0;
1962
David Ahern4bb09192013-09-04 12:37:43 -06001963 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001964 trace->base_time = sample->time;
1965
David Ahern31605652013-12-04 19:41:41 -07001966 if (handler) {
1967 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001968 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07001969 }
David Ahern6810fc92013-08-28 22:29:52 -06001970
1971 return err;
1972}
1973
David Ahernbdc89662013-08-28 22:29:53 -06001974static int parse_target_str(struct trace *trace)
1975{
1976 if (trace->opts.target.pid) {
1977 trace->pid_list = intlist__new(trace->opts.target.pid);
1978 if (trace->pid_list == NULL) {
1979 pr_err("Error parsing process id string\n");
1980 return -EINVAL;
1981 }
1982 }
1983
1984 if (trace->opts.target.tid) {
1985 trace->tid_list = intlist__new(trace->opts.target.tid);
1986 if (trace->tid_list == NULL) {
1987 pr_err("Error parsing thread id string\n");
1988 return -EINVAL;
1989 }
1990 }
1991
1992 return 0;
1993}
1994
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001995static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06001996{
1997 unsigned int rec_argc, i, j;
1998 const char **rec_argv;
1999 const char * const record_args[] = {
2000 "record",
2001 "-R",
2002 "-m", "1024",
2003 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002004 };
2005
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002006 const char * const sc_args[] = { "-e", };
2007 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2008 const char * const majpf_args[] = { "-e", "major-faults" };
2009 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2010 const char * const minpf_args[] = { "-e", "minor-faults" };
2011 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2012
David Ahern9aca7f12013-12-04 19:41:39 -07002013 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002014 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2015 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002016 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2017
2018 if (rec_argv == NULL)
2019 return -ENOMEM;
2020
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002021 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002022 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002023 rec_argv[j++] = record_args[i];
2024
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002025 if (trace->trace_syscalls) {
2026 for (i = 0; i < sc_args_nr; i++)
2027 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002028
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002029 /* event string may be different for older kernels - e.g., RHEL6 */
2030 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2031 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2032 else if (is_valid_tracepoint("syscalls:sys_enter"))
2033 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2034 else {
2035 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2036 return -1;
2037 }
David Ahern9aca7f12013-12-04 19:41:39 -07002038 }
David Ahern9aca7f12013-12-04 19:41:39 -07002039
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002040 if (trace->trace_pgfaults & TRACE_PFMAJ)
2041 for (i = 0; i < majpf_args_nr; i++)
2042 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002043
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002044 if (trace->trace_pgfaults & TRACE_PFMIN)
2045 for (i = 0; i < minpf_args_nr; i++)
2046 rec_argv[j++] = minpf_args[i];
2047
2048 for (i = 0; i < (unsigned int)argc; i++)
2049 rec_argv[j++] = argv[i];
2050
2051 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002052}
2053
David Ahernbf2575c2013-10-08 21:26:53 -06002054static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2055
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002056static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
2057{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002058 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002059 if (evsel == NULL)
2060 return;
2061
2062 if (perf_evsel__field(evsel, "pathname") == NULL) {
2063 perf_evsel__delete(evsel);
2064 return;
2065 }
2066
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002067 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002068 perf_evlist__add(evlist, evsel);
2069}
2070
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002071static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2072 u64 config)
2073{
2074 struct perf_evsel *evsel;
2075 struct perf_event_attr attr = {
2076 .type = PERF_TYPE_SOFTWARE,
2077 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002078 };
2079
2080 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002081 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002082
2083 event_attr_init(&attr);
2084
2085 evsel = perf_evsel__new(&attr);
2086 if (!evsel)
2087 return -ENOMEM;
2088
2089 evsel->handler = trace__pgfault;
2090 perf_evlist__add(evlist, evsel);
2091
2092 return 0;
2093}
2094
Namhyung Kimf15eb532012-10-05 14:02:16 +09002095static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002096{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002097 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002098 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002099 int err = -1, i;
2100 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002101 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002102 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002103
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002104 trace->live = true;
2105
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002106 if (trace->trace_syscalls &&
2107 perf_evlist__add_syscall_newtp(evlist, trace__sys_enter,
2108 trace__sys_exit))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002109 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002110
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002111 if (trace->trace_syscalls)
2112 perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002113
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002114 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002115 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002116 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002117 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002118
2119 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2120 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002121 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002122
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002123 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002124 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2125 trace__sched_stat_runtime))
2126 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002127
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002128 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2129 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002130 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002131 goto out_delete_evlist;
2132 }
2133
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002134 err = trace__symbols_init(trace, evlist);
2135 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002136 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002137 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002138 }
2139
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002140 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002141
Namhyung Kimf15eb532012-10-05 14:02:16 +09002142 signal(SIGCHLD, sig_handler);
2143 signal(SIGINT, sig_handler);
2144
2145 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002146 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002147 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002148 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002149 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002150 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002151 }
2152 }
2153
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002154 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002155 if (err < 0)
2156 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002157
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002158 /*
2159 * Better not use !target__has_task() here because we need to cover the
2160 * case where no threads were specified in the command line, but a
2161 * workload was, and in that case we will fill in the thread_map when
2162 * we fork the workload in perf_evlist__prepare_workload.
2163 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002164 if (trace->filter_pids.nr > 0)
2165 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
2166 else if (evlist->threads->map[0] == -1)
2167 err = perf_evlist__set_filter_pid(evlist, getpid());
2168
2169 if (err < 0) {
2170 printf("err=%d,%s\n", -err, strerror(-err));
2171 exit(1);
2172 }
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002173
Jiri Olsaf8850372013-11-28 17:57:22 +01002174 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002175 if (err < 0)
2176 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002177
Namhyung Kimf15eb532012-10-05 14:02:16 +09002178 if (forks)
2179 perf_evlist__start_workload(evlist);
Arnaldo Carvalho de Melof7aa2222015-02-03 13:25:39 -03002180 else
2181 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002182
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002183 trace->multiple_threads = evlist->threads->map[0] == -1 ||
2184 evlist->threads->nr > 1 ||
2185 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002186again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002187 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002188
2189 for (i = 0; i < evlist->nr_mmaps; i++) {
2190 union perf_event *event;
2191
2192 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
2193 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002194 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002195 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002196
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002197 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002198
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002199 err = perf_evlist__parse_sample(evlist, event, &sample);
2200 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002201 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002202 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002203 }
2204
David Ahern4bb09192013-09-04 12:37:43 -06002205 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002206 trace->base_time = sample.time;
2207
2208 if (type != PERF_RECORD_SAMPLE) {
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02002209 trace__process_event(trace, trace->host, event, &sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002210 continue;
2211 }
2212
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002213 evsel = perf_evlist__id2evsel(evlist, sample.id);
2214 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002215 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002216 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002217 }
2218
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002219 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2220 sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002221 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 -03002222 perf_evsel__name(evsel), sample.tid,
2223 sample.cpu, sample.raw_size);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002224 goto next_event;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002225 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002226
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002227 handler = evsel->handler;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002228 handler(trace, evsel, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002229next_event:
2230 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002231
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002232 if (interrupted)
2233 goto out_disable;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002234 }
2235 }
2236
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002237 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002238 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002239
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002240 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2241 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2242 draining = true;
2243
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002244 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002245 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002246 } else {
2247 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002248 }
2249
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002250out_disable:
2251 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002252
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002253 if (!err) {
2254 if (trace->summary)
2255 trace__fprintf_thread_summary(trace, trace->output);
2256
2257 if (trace->show_tool_stats) {
2258 fprintf(trace->output, "Stats:\n "
2259 " vfs_getname : %" PRIu64 "\n"
2260 " proc_getname: %" PRIu64 "\n",
2261 trace->stats.vfs_getname,
2262 trace->stats.proc_getname);
2263 }
2264 }
David Ahernbf2575c2013-10-08 21:26:53 -06002265
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002266out_delete_evlist:
2267 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002268 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002269 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002270 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002271{
2272 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002273
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002274out_error_sched_stat_runtime:
2275 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
2276 goto out_error;
2277
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002278out_error_raw_syscalls:
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002279 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002280 goto out_error;
2281
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002282out_error_mmap:
2283 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2284 goto out_error;
2285
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002286out_error_open:
2287 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2288
2289out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002290 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302291 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002292}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002293out_error_mem:
2294 fprintf(trace->output, "Not enough memory to run!\n");
2295 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002296}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002297
David Ahern6810fc92013-08-28 22:29:52 -06002298static int trace__replay(struct trace *trace)
2299{
2300 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002301 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002302 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002303 struct perf_data_file file = {
2304 .path = input_name,
2305 .mode = PERF_DATA_MODE_READ,
2306 };
David Ahern6810fc92013-08-28 22:29:52 -06002307 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002308 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002309 int err = -1;
2310
2311 trace->tool.sample = trace__process_sample;
2312 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002313 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002314 trace->tool.comm = perf_event__process_comm;
2315 trace->tool.exit = perf_event__process_exit;
2316 trace->tool.fork = perf_event__process_fork;
2317 trace->tool.attr = perf_event__process_attr;
2318 trace->tool.tracing_data = perf_event__process_tracing_data;
2319 trace->tool.build_id = perf_event__process_build_id;
2320
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002321 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002322 trace->tool.ordering_requires_timestamps = true;
2323
2324 /* add tid to output */
2325 trace->multiple_threads = true;
2326
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002327 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002328 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002329 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002330
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002331 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002332 goto out;
2333
David Ahern8fb598e2013-09-28 13:13:00 -06002334 trace->host = &session->machines.host;
2335
David Ahern6810fc92013-08-28 22:29:52 -06002336 err = perf_session__set_tracepoints_handlers(session, handlers);
2337 if (err)
2338 goto out;
2339
Namhyung Kim003824e2013-11-12 15:25:00 +09002340 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2341 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002342 /* older kernels have syscalls tp versus raw_syscalls */
2343 if (evsel == NULL)
2344 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2345 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002346
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002347 if (evsel &&
2348 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2349 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002350 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2351 goto out;
2352 }
2353
2354 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2355 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002356 if (evsel == NULL)
2357 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2358 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002359 if (evsel &&
2360 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2361 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002362 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002363 goto out;
2364 }
2365
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002366 evlist__for_each(session->evlist, evsel) {
2367 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2368 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2369 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2370 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2371 evsel->handler = trace__pgfault;
2372 }
2373
David Ahernbdc89662013-08-28 22:29:53 -06002374 err = parse_target_str(trace);
2375 if (err != 0)
2376 goto out;
2377
David Ahern6810fc92013-08-28 22:29:52 -06002378 setup_pager();
2379
2380 err = perf_session__process_events(session, &trace->tool);
2381 if (err)
2382 pr_err("Failed to process events, error %d", err);
2383
David Ahernbf2575c2013-10-08 21:26:53 -06002384 else if (trace->summary)
2385 trace__fprintf_thread_summary(trace, trace->output);
2386
David Ahern6810fc92013-08-28 22:29:52 -06002387out:
2388 perf_session__delete(session);
2389
2390 return err;
2391}
2392
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002393static size_t trace__fprintf_threads_header(FILE *fp)
2394{
2395 size_t printed;
2396
Pekka Enberg99ff7152013-11-12 16:42:14 +02002397 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002398
2399 return printed;
2400}
2401
2402static size_t thread__dump_stats(struct thread_trace *ttrace,
2403 struct trace *trace, FILE *fp)
2404{
2405 struct stats *stats;
2406 size_t printed = 0;
2407 struct syscall *sc;
2408 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2409
2410 if (inode == NULL)
2411 return 0;
2412
2413 printed += fprintf(fp, "\n");
2414
Pekka Enberg27a778b2013-11-13 14:21:48 +02002415 printed += fprintf(fp, " syscall calls min avg max stddev\n");
2416 printed += fprintf(fp, " (msec) (msec) (msec) (%%)\n");
2417 printed += fprintf(fp, " --------------- -------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002418
David Ahernbf2575c2013-10-08 21:26:53 -06002419 /* each int_node is a syscall */
2420 while (inode) {
2421 stats = inode->priv;
2422 if (stats) {
2423 double min = (double)(stats->min) / NSEC_PER_MSEC;
2424 double max = (double)(stats->max) / NSEC_PER_MSEC;
2425 double avg = avg_stats(stats);
2426 double pct;
2427 u64 n = (u64) stats->n;
2428
2429 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2430 avg /= NSEC_PER_MSEC;
2431
2432 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002433 printed += fprintf(fp, " %-15s", sc->name);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002434 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f",
Pekka Enberg7f7a4132013-11-12 16:10:10 +02002435 n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002436 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002437 }
2438
2439 inode = intlist__next(inode);
2440 }
2441
2442 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002443
2444 return printed;
2445}
2446
David Ahern896cbb52013-09-28 13:12:59 -06002447/* struct used to pass data to per-thread function */
2448struct summary_data {
2449 FILE *fp;
2450 struct trace *trace;
2451 size_t printed;
2452};
2453
2454static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2455{
2456 struct summary_data *data = priv;
2457 FILE *fp = data->fp;
2458 size_t printed = data->printed;
2459 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002460 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002461 double ratio;
2462
2463 if (ttrace == NULL)
2464 return 0;
2465
2466 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2467
Pekka Enberg15e65c62013-11-14 18:43:30 +02002468 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002469 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002470 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002471 if (ttrace->pfmaj)
2472 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2473 if (ttrace->pfmin)
2474 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002475 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002476 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002477
2478 data->printed += printed;
2479
2480 return 0;
2481}
2482
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002483static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2484{
David Ahern896cbb52013-09-28 13:12:59 -06002485 struct summary_data data = {
2486 .fp = fp,
2487 .trace = trace
2488 };
2489 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002490
David Ahern896cbb52013-09-28 13:12:59 -06002491 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002492
David Ahern896cbb52013-09-28 13:12:59 -06002493 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002494}
2495
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002496static int trace__set_duration(const struct option *opt, const char *str,
2497 int unset __maybe_unused)
2498{
2499 struct trace *trace = opt->value;
2500
2501 trace->duration_filter = atof(str);
2502 return 0;
2503}
2504
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002505static int trace__set_filter_pids(const struct option *opt, const char *str,
2506 int unset __maybe_unused)
2507{
2508 int ret = -1;
2509 size_t i;
2510 struct trace *trace = opt->value;
2511 /*
2512 * FIXME: introduce a intarray class, plain parse csv and create a
2513 * { int nr, int entries[] } struct...
2514 */
2515 struct intlist *list = intlist__new(str);
2516
2517 if (list == NULL)
2518 return -1;
2519
2520 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2521 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2522
2523 if (trace->filter_pids.entries == NULL)
2524 goto out;
2525
2526 trace->filter_pids.entries[0] = getpid();
2527
2528 for (i = 1; i < trace->filter_pids.nr; ++i)
2529 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2530
2531 intlist__delete(list);
2532 ret = 0;
2533out:
2534 return ret;
2535}
2536
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002537static int trace__open_output(struct trace *trace, const char *filename)
2538{
2539 struct stat st;
2540
2541 if (!stat(filename, &st) && st.st_size) {
2542 char oldname[PATH_MAX];
2543
2544 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2545 unlink(oldname);
2546 rename(filename, oldname);
2547 }
2548
2549 trace->output = fopen(filename, "w");
2550
2551 return trace->output == NULL ? -errno : 0;
2552}
2553
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002554static int parse_pagefaults(const struct option *opt, const char *str,
2555 int unset __maybe_unused)
2556{
2557 int *trace_pgfaults = opt->value;
2558
2559 if (strcmp(str, "all") == 0)
2560 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2561 else if (strcmp(str, "maj") == 0)
2562 *trace_pgfaults |= TRACE_PFMAJ;
2563 else if (strcmp(str, "min") == 0)
2564 *trace_pgfaults |= TRACE_PFMIN;
2565 else
2566 return -1;
2567
2568 return 0;
2569}
2570
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002571static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2572{
2573 struct perf_evsel *evsel;
2574
2575 evlist__for_each(evlist, evsel)
2576 evsel->handler = handler;
2577}
2578
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002579int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2580{
2581 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002582 "perf trace [<options>] [<command>]",
2583 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002584 "perf trace record [<options>] [<command>]",
2585 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002586 NULL
2587 };
2588 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002589 .audit = {
2590 .machine = audit_detect_machine(),
2591 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2592 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002593 .syscalls = {
2594 . max = -1,
2595 },
2596 .opts = {
2597 .target = {
2598 .uid = UINT_MAX,
2599 .uses_mmap = true,
2600 },
2601 .user_freq = UINT_MAX,
2602 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002603 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002604 .mmap_pages = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002605 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002606 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002607 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002608 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002609 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002610 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002611 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002612 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002613 OPT_CALLBACK(0, "event", &trace.evlist, "event",
2614 "event selector. use 'perf list' to list available events",
2615 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002616 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2617 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002618 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002619 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
2620 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002621 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002622 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002623 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2624 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002625 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002626 "trace events on existing thread id"),
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002627 OPT_CALLBACK(0, "filter-pids", &trace, "float",
2628 "show only events with duration > N.M ms", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002629 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002630 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002631 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002632 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002633 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002634 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002635 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2636 "number of mmap data pages",
2637 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002638 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002639 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002640 OPT_CALLBACK(0, "duration", &trace, "float",
2641 "show only events with duration > N.M ms",
2642 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002643 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002644 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002645 OPT_BOOLEAN('T', "time", &trace.full_time,
2646 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002647 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2648 "Show only syscall summary with statistics"),
2649 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2650 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002651 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2652 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002653 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002654 OPT_END()
2655 };
2656 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002657 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002658
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002659 trace.evlist = perf_evlist__new();
2660 if (trace.evlist == NULL)
2661 return -ENOMEM;
2662
2663 if (trace.evlist == NULL) {
2664 pr_err("Not enough memory to run!\n");
2665 goto out;
2666 }
2667
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002668 argc = parse_options(argc, argv, trace_options, trace_usage,
2669 PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002670
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002671 if (trace.trace_pgfaults) {
2672 trace.opts.sample_address = true;
2673 trace.opts.sample_time = true;
2674 }
2675
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002676 if (trace.evlist->nr_entries > 0)
2677 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2678
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002679 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2680 return trace__record(&trace, argc-1, &argv[1]);
2681
2682 /* summary_only implies summary option, but don't overwrite summary if set */
2683 if (trace.summary_only)
2684 trace.summary = trace.summary_only;
2685
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002686 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2687 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002688 pr_err("Please specify something to trace.\n");
2689 return -1;
2690 }
2691
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002692 if (output_name != NULL) {
2693 err = trace__open_output(&trace, output_name);
2694 if (err < 0) {
2695 perror("failed to create output file");
2696 goto out;
2697 }
2698 }
2699
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002700 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002701 const char *s = ev_qualifier_str;
2702
2703 trace.not_ev_qualifier = *s == '!';
2704 if (trace.not_ev_qualifier)
2705 ++s;
2706 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002707 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002708 fputs("Not enough memory to parse event qualifier",
2709 trace.output);
2710 err = -ENOMEM;
2711 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002712 }
2713 }
2714
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002715 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002716 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002717 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002718 fprintf(trace.output, "%s", bf);
2719 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002720 }
2721
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002722 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002723 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002724 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002725 fprintf(trace.output, "%s", bf);
2726 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002727 }
2728
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002729 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002730 trace.opts.target.system_wide = true;
2731
David Ahern6810fc92013-08-28 22:29:52 -06002732 if (input_name)
2733 err = trace__replay(&trace);
2734 else
2735 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002736
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002737out_close:
2738 if (output_name != NULL)
2739 fclose(trace.output);
2740out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002741 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002742}