blob: 8a83bd83532752f494ae608ae22f2234f5ea000f [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,
932 .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,
935 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
936 { .name = "dup2", .errmsg = true,
937 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
938 { .name = "dup3", .errmsg = true,
939 .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,
946 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
947 { .name = "fallocate", .errmsg = true,
948 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
949 { .name = "fchdir", .errmsg = true,
950 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
951 { .name = "fchmod", .errmsg = true,
952 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
953 { .name = "fchmodat", .errmsg = true,
954 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
955 { .name = "fchown", .errmsg = true,
956 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
957 { .name = "fchownat", .errmsg = true,
958 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
959 { .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,
964 .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,
969 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
970 { .name = "fstat", .errmsg = true, .alias = "newfstat",
971 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
972 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
973 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
974 { .name = "fstatfs", .errmsg = true,
975 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
976 { .name = "fsync", .errmsg = true,
977 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
978 { .name = "ftruncate", .errmsg = true,
979 .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,
983 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
984 { .name = "getdents", .errmsg = true,
985 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
986 { .name = "getdents64", .errmsg = true,
987 .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 Melo75b757ca2013-09-24 11:04:32 -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,
1005 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
1006 { .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,
1015 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
1016 { .name = "mknodat", .errmsg = true,
1017 .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,
1039 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1040 { .name = "newfstatat", .errmsg = true,
1041 .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",
1055 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1056 { .name = "preadv", .errmsg = true, .alias = "pread",
1057 .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",
1060 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1061 { .name = "pwritev", .errmsg = true,
1062 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1063 { .name = "read", .errmsg = true,
1064 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1065 { .name = "readlinkat", .errmsg = true,
1066 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1067 { .name = "readv", .errmsg = true,
1068 .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,
1076 .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,
1094 .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,
1105 .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,
1116 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1117 { .name = "writev", .errmsg = true,
1118 .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
1192 if (thread->priv == NULL)
1193 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001194
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001195 if (thread->priv == NULL)
1196 goto fail;
1197
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001198 ttrace = thread->priv;
1199 ++ttrace->nr_events;
1200
1201 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001202fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001203 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001204 "WARNING: not enough memory, dropping samples!\n");
1205 return NULL;
1206}
1207
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001208#define TRACE_PFMAJ (1 << 0)
1209#define TRACE_PFMIN (1 << 1)
1210
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001211struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001212 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001213 struct {
1214 int machine;
1215 int open_id;
1216 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001217 struct {
1218 int max;
1219 struct syscall *table;
1220 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001221 struct record_opts opts;
David Ahern8fb598e2013-09-28 13:13:00 -06001222 struct machine *host;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001223 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001224 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001225 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001226 struct strlist *ev_qualifier;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001227 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -06001228 struct intlist *tid_list;
1229 struct intlist *pid_list;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001230 double duration_filter;
1231 double runtime_ms;
1232 struct {
1233 u64 vfs_getname,
1234 proc_getname;
1235 } stats;
1236 bool not_ev_qualifier;
1237 bool live;
1238 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001239 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001240 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001241 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001242 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001243 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001244 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001245 bool trace_syscalls;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001246 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001247};
1248
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001249static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001250{
1251 struct thread_trace *ttrace = thread->priv;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001252
1253 if (fd > ttrace->paths.max) {
1254 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1255
1256 if (npath == NULL)
1257 return -1;
1258
1259 if (ttrace->paths.max != -1) {
1260 memset(npath + ttrace->paths.max + 1, 0,
1261 (fd - ttrace->paths.max) * sizeof(char *));
1262 } else {
1263 memset(npath, 0, (fd + 1) * sizeof(char *));
1264 }
1265
1266 ttrace->paths.table = npath;
1267 ttrace->paths.max = fd;
1268 }
1269
1270 ttrace->paths.table[fd] = strdup(pathname);
1271
1272 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1273}
1274
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001275static int thread__read_fd_path(struct thread *thread, int fd)
1276{
1277 char linkname[PATH_MAX], pathname[PATH_MAX];
1278 struct stat st;
1279 int ret;
1280
1281 if (thread->pid_ == thread->tid) {
1282 scnprintf(linkname, sizeof(linkname),
1283 "/proc/%d/fd/%d", thread->pid_, fd);
1284 } else {
1285 scnprintf(linkname, sizeof(linkname),
1286 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1287 }
1288
1289 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1290 return -1;
1291
1292 ret = readlink(linkname, pathname, sizeof(pathname));
1293
1294 if (ret < 0 || ret > st.st_size)
1295 return -1;
1296
1297 pathname[ret] = '\0';
1298 return trace__set_fd_pathname(thread, fd, pathname);
1299}
1300
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001301static const char *thread__fd_path(struct thread *thread, int fd,
1302 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001303{
1304 struct thread_trace *ttrace = thread->priv;
1305
1306 if (ttrace == NULL)
1307 return NULL;
1308
1309 if (fd < 0)
1310 return NULL;
1311
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001312 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001313 if (!trace->live)
1314 return NULL;
1315 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001316 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001317 return NULL;
1318 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001319
1320 return ttrace->paths.table[fd];
1321}
1322
1323static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1324 struct syscall_arg *arg)
1325{
1326 int fd = arg->val;
1327 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001328 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001329
1330 if (path)
1331 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1332
1333 return printed;
1334}
1335
1336static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1337 struct syscall_arg *arg)
1338{
1339 int fd = arg->val;
1340 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1341 struct thread_trace *ttrace = arg->thread->priv;
1342
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001343 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1344 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001345
1346 return printed;
1347}
1348
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001349static bool trace__filter_duration(struct trace *trace, double t)
1350{
1351 return t < (trace->duration_filter * NSEC_PER_MSEC);
1352}
1353
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001354static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1355{
1356 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1357
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001358 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001359}
1360
Namhyung Kimf15eb532012-10-05 14:02:16 +09001361static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001362static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001363
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001364static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001365{
1366 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001367 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001368}
1369
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001370static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001371 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001372{
1373 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001374 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001375
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001376 if (trace->multiple_threads) {
1377 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001378 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001379 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001380 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001381
1382 return printed;
1383}
1384
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001385static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001386 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001387{
1388 int ret = 0;
1389
1390 switch (event->header.type) {
1391 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001392 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001393 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001394 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001395 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001396 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001397 break;
1398 }
1399
1400 return ret;
1401}
1402
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001403static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001404 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001405 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001406 struct machine *machine)
1407{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001408 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001409 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001410}
1411
1412static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1413{
1414 int err = symbol__init();
1415
1416 if (err)
1417 return err;
1418
David Ahern8fb598e2013-09-28 13:13:00 -06001419 trace->host = machine__new_host();
1420 if (trace->host == NULL)
1421 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001422
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001423 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
1424 evlist->threads, trace__tool_process, false);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001425 if (err)
1426 symbol__exit();
1427
1428 return err;
1429}
1430
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001431static int syscall__set_arg_fmts(struct syscall *sc)
1432{
1433 struct format_field *field;
1434 int idx = 0;
1435
1436 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1437 if (sc->arg_scnprintf == NULL)
1438 return -1;
1439
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001440 if (sc->fmt)
1441 sc->arg_parm = sc->fmt->arg_parm;
1442
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001443 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001444 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1445 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1446 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001447 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1448 ++idx;
1449 }
1450
1451 return 0;
1452}
1453
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001454static int trace__read_syscall_info(struct trace *trace, int id)
1455{
1456 char tp_name[128];
1457 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001458 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001459
1460 if (name == NULL)
1461 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001462
1463 if (id > trace->syscalls.max) {
1464 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1465
1466 if (nsyscalls == NULL)
1467 return -1;
1468
1469 if (trace->syscalls.max != -1) {
1470 memset(nsyscalls + trace->syscalls.max + 1, 0,
1471 (id - trace->syscalls.max) * sizeof(*sc));
1472 } else {
1473 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1474 }
1475
1476 trace->syscalls.table = nsyscalls;
1477 trace->syscalls.max = id;
1478 }
1479
1480 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001481 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001482
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001483 if (trace->ev_qualifier) {
1484 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1485
1486 if (!(in ^ trace->not_ev_qualifier)) {
1487 sc->filtered = true;
1488 /*
1489 * No need to do read tracepoint information since this will be
1490 * filtered out.
1491 */
1492 return 0;
1493 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001494 }
1495
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001496 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001497
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001498 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001499 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001500
1501 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1502 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001503 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001504 }
1505
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001506 if (sc->tp_format == NULL)
1507 return -1;
1508
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001509 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1510
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001511 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001512}
1513
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001514static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001515 unsigned long *args, struct trace *trace,
1516 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001517{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001518 size_t printed = 0;
1519
1520 if (sc->tp_format != NULL) {
1521 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001522 u8 bit = 1;
1523 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001524 .idx = 0,
1525 .mask = 0,
1526 .trace = trace,
1527 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001528 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001529
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001530 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001531 field = field->next, ++arg.idx, bit <<= 1) {
1532 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001533 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001534 /*
1535 * Suppress this argument if its value is zero and
1536 * and we don't have a string associated in an
1537 * strarray for it.
1538 */
1539 if (args[arg.idx] == 0 &&
1540 !(sc->arg_scnprintf &&
1541 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1542 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001543 continue;
1544
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001545 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001546 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001547 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1548 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001549 if (sc->arg_parm)
1550 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001551 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1552 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001553 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001554 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001555 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001556 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001557 }
1558 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001559 int i = 0;
1560
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001561 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001562 printed += scnprintf(bf + printed, size - printed,
1563 "%sarg%d: %ld",
1564 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001565 ++i;
1566 }
1567 }
1568
1569 return printed;
1570}
1571
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001572typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001573 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001574 struct perf_sample *sample);
1575
1576static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001577 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001578{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001579
1580 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001581
1582 /*
1583 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1584 * before that, leaving at a higher verbosity level till that is
1585 * explained. Reproduced with plain ftrace with:
1586 *
1587 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1588 * grep "NR -1 " /t/trace_pipe
1589 *
1590 * After generating some load on the machine.
1591 */
1592 if (verbose > 1) {
1593 static u64 n;
1594 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1595 id, perf_evsel__name(evsel), ++n);
1596 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001597 return NULL;
1598 }
1599
1600 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1601 trace__read_syscall_info(trace, id))
1602 goto out_cant_read;
1603
1604 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1605 goto out_cant_read;
1606
1607 return &trace->syscalls.table[id];
1608
1609out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001610 if (verbose) {
1611 fprintf(trace->output, "Problems reading syscall %d", id);
1612 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1613 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1614 fputs(" information\n", trace->output);
1615 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001616 return NULL;
1617}
1618
David Ahernbf2575c2013-10-08 21:26:53 -06001619static void thread__update_stats(struct thread_trace *ttrace,
1620 int id, struct perf_sample *sample)
1621{
1622 struct int_node *inode;
1623 struct stats *stats;
1624 u64 duration = 0;
1625
1626 inode = intlist__findnew(ttrace->syscall_stats, id);
1627 if (inode == NULL)
1628 return;
1629
1630 stats = inode->priv;
1631 if (stats == NULL) {
1632 stats = malloc(sizeof(struct stats));
1633 if (stats == NULL)
1634 return;
1635 init_stats(stats);
1636 inode->priv = stats;
1637 }
1638
1639 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1640 duration = sample->time - ttrace->entry_time;
1641
1642 update_stats(stats, duration);
1643}
1644
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001645static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001646 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001647 struct perf_sample *sample)
1648{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001649 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001650 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001651 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001652 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001653 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001654 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001655 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001656
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001657 if (sc == NULL)
1658 return -1;
1659
1660 if (sc->filtered)
1661 return 0;
1662
David Ahern8fb598e2013-09-28 13:13:00 -06001663 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001664 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001665 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001666 return -1;
1667
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001668 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001669
1670 if (ttrace->entry_str == NULL) {
1671 ttrace->entry_str = malloc(1024);
1672 if (!ttrace->entry_str)
1673 return -1;
1674 }
1675
1676 ttrace->entry_time = sample->time;
1677 msg = ttrace->entry_str;
1678 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1679
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001680 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1681 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001682
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001683 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001684 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001685 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1686 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001687 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001688 } else
1689 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001690
1691 return 0;
1692}
1693
1694static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001695 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001696 struct perf_sample *sample)
1697{
1698 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001699 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001700 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001701 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001702 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001703 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001704
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001705 if (sc == NULL)
1706 return -1;
1707
1708 if (sc->filtered)
1709 return 0;
1710
David Ahern8fb598e2013-09-28 13:13:00 -06001711 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001712 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001713 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001714 return -1;
1715
David Ahernbf2575c2013-10-08 21:26:53 -06001716 if (trace->summary)
1717 thread__update_stats(ttrace, id, sample);
1718
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001719 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001720
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001721 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1722 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1723 trace->last_vfs_getname = NULL;
1724 ++trace->stats.vfs_getname;
1725 }
1726
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001727 ttrace->exit_time = sample->time;
1728
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001729 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001730 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001731 if (trace__filter_duration(trace, duration))
1732 goto out;
1733 } else if (trace->duration_filter)
1734 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001735
David Ahernfd2eaba2013-11-12 09:31:15 -07001736 if (trace->summary_only)
1737 goto out;
1738
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001739 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001740
1741 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001742 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001743 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001744 fprintf(trace->output, " ... [");
1745 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1746 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001747 }
1748
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001749 if (sc->fmt == NULL) {
1750signed_print:
1751 fprintf(trace->output, ") = %d", ret);
1752 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001753 char bf[256];
1754 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1755 *e = audit_errno_to_name(-ret);
1756
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001757 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001758 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001759 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001760 else if (sc->fmt->hexret)
1761 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001762 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001763 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001764
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001765 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001766out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001767 ttrace->entry_pending = false;
1768
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001769 return 0;
1770}
1771
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001772static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001773 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001774 struct perf_sample *sample)
1775{
1776 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1777 return 0;
1778}
1779
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001780static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001781 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001782 struct perf_sample *sample)
1783{
1784 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1785 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001786 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001787 sample->pid,
1788 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001789 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001790
1791 if (ttrace == NULL)
1792 goto out_dump;
1793
1794 ttrace->runtime_ms += runtime_ms;
1795 trace->runtime_ms += runtime_ms;
1796 return 0;
1797
1798out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001799 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001800 evsel->name,
1801 perf_evsel__strval(evsel, sample, "comm"),
1802 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1803 runtime,
1804 perf_evsel__intval(evsel, sample, "vruntime"));
1805 return 0;
1806}
1807
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001808static void print_location(FILE *f, struct perf_sample *sample,
1809 struct addr_location *al,
1810 bool print_dso, bool print_sym)
1811{
1812
1813 if ((verbose || print_dso) && al->map)
1814 fprintf(f, "%s@", al->map->dso->long_name);
1815
1816 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001817 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001818 al->addr - al->sym->start);
1819 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001820 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001821 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001822 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001823}
1824
1825static int trace__pgfault(struct trace *trace,
1826 struct perf_evsel *evsel,
1827 union perf_event *event,
1828 struct perf_sample *sample)
1829{
1830 struct thread *thread;
1831 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1832 struct addr_location al;
1833 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001834 struct thread_trace *ttrace;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001835
1836 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001837 ttrace = thread__trace(thread, trace->output);
1838 if (ttrace == NULL)
1839 return -1;
1840
1841 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1842 ttrace->pfmaj++;
1843 else
1844 ttrace->pfmin++;
1845
1846 if (trace->summary_only)
1847 return 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001848
1849 thread__find_addr_location(thread, trace->host, cpumode, MAP__FUNCTION,
1850 sample->ip, &al);
1851
1852 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
1853
1854 fprintf(trace->output, "%sfault [",
1855 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1856 "maj" : "min");
1857
1858 print_location(trace->output, sample, &al, false, true);
1859
1860 fprintf(trace->output, "] => ");
1861
1862 thread__find_addr_location(thread, trace->host, cpumode, MAP__VARIABLE,
1863 sample->addr, &al);
1864
1865 if (!al.map) {
1866 thread__find_addr_location(thread, trace->host, cpumode,
1867 MAP__FUNCTION, sample->addr, &al);
1868
1869 if (al.map)
1870 map_type = 'x';
1871 else
1872 map_type = '?';
1873 }
1874
1875 print_location(trace->output, sample, &al, true, false);
1876
1877 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
1878
1879 return 0;
1880}
1881
David Ahernbdc89662013-08-28 22:29:53 -06001882static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1883{
1884 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1885 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1886 return false;
1887
1888 if (trace->pid_list || trace->tid_list)
1889 return true;
1890
1891 return false;
1892}
1893
David Ahern6810fc92013-08-28 22:29:52 -06001894static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001895 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001896 struct perf_sample *sample,
1897 struct perf_evsel *evsel,
1898 struct machine *machine __maybe_unused)
1899{
1900 struct trace *trace = container_of(tool, struct trace, tool);
1901 int err = 0;
1902
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001903 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001904
David Ahernbdc89662013-08-28 22:29:53 -06001905 if (skip_sample(trace, sample))
1906 return 0;
1907
David Ahern4bb09192013-09-04 12:37:43 -06001908 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001909 trace->base_time = sample->time;
1910
David Ahern31605652013-12-04 19:41:41 -07001911 if (handler) {
1912 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001913 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07001914 }
David Ahern6810fc92013-08-28 22:29:52 -06001915
1916 return err;
1917}
1918
David Ahernbdc89662013-08-28 22:29:53 -06001919static int parse_target_str(struct trace *trace)
1920{
1921 if (trace->opts.target.pid) {
1922 trace->pid_list = intlist__new(trace->opts.target.pid);
1923 if (trace->pid_list == NULL) {
1924 pr_err("Error parsing process id string\n");
1925 return -EINVAL;
1926 }
1927 }
1928
1929 if (trace->opts.target.tid) {
1930 trace->tid_list = intlist__new(trace->opts.target.tid);
1931 if (trace->tid_list == NULL) {
1932 pr_err("Error parsing thread id string\n");
1933 return -EINVAL;
1934 }
1935 }
1936
1937 return 0;
1938}
1939
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001940static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06001941{
1942 unsigned int rec_argc, i, j;
1943 const char **rec_argv;
1944 const char * const record_args[] = {
1945 "record",
1946 "-R",
1947 "-m", "1024",
1948 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06001949 };
1950
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001951 const char * const sc_args[] = { "-e", };
1952 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
1953 const char * const majpf_args[] = { "-e", "major-faults" };
1954 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
1955 const char * const minpf_args[] = { "-e", "minor-faults" };
1956 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
1957
David Ahern9aca7f12013-12-04 19:41:39 -07001958 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001959 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
1960 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06001961 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1962
1963 if (rec_argv == NULL)
1964 return -ENOMEM;
1965
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001966 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06001967 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001968 rec_argv[j++] = record_args[i];
1969
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001970 if (trace->trace_syscalls) {
1971 for (i = 0; i < sc_args_nr; i++)
1972 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06001973
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001974 /* event string may be different for older kernels - e.g., RHEL6 */
1975 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
1976 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
1977 else if (is_valid_tracepoint("syscalls:sys_enter"))
1978 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
1979 else {
1980 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
1981 return -1;
1982 }
David Ahern9aca7f12013-12-04 19:41:39 -07001983 }
David Ahern9aca7f12013-12-04 19:41:39 -07001984
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001985 if (trace->trace_pgfaults & TRACE_PFMAJ)
1986 for (i = 0; i < majpf_args_nr; i++)
1987 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06001988
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001989 if (trace->trace_pgfaults & TRACE_PFMIN)
1990 for (i = 0; i < minpf_args_nr; i++)
1991 rec_argv[j++] = minpf_args[i];
1992
1993 for (i = 0; i < (unsigned int)argc; i++)
1994 rec_argv[j++] = argv[i];
1995
1996 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06001997}
1998
David Ahernbf2575c2013-10-08 21:26:53 -06001999static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2000
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002001static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
2002{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002003 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002004 if (evsel == NULL)
2005 return;
2006
2007 if (perf_evsel__field(evsel, "pathname") == NULL) {
2008 perf_evsel__delete(evsel);
2009 return;
2010 }
2011
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002012 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002013 perf_evlist__add(evlist, evsel);
2014}
2015
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002016static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2017 u64 config)
2018{
2019 struct perf_evsel *evsel;
2020 struct perf_event_attr attr = {
2021 .type = PERF_TYPE_SOFTWARE,
2022 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002023 };
2024
2025 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002026 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002027
2028 event_attr_init(&attr);
2029
2030 evsel = perf_evsel__new(&attr);
2031 if (!evsel)
2032 return -ENOMEM;
2033
2034 evsel->handler = trace__pgfault;
2035 perf_evlist__add(evlist, evsel);
2036
2037 return 0;
2038}
2039
Namhyung Kimf15eb532012-10-05 14:02:16 +09002040static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002041{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09002042 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002043 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002044 int err = -1, i;
2045 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002046 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002047
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002048 trace->live = true;
2049
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002050 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002051 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002052 goto out;
2053 }
2054
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002055 if (trace->trace_syscalls &&
2056 perf_evlist__add_syscall_newtp(evlist, trace__sys_enter,
2057 trace__sys_exit))
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302058 goto out_error_tp;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002059
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002060 if (trace->trace_syscalls)
2061 perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002062
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002063 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
2064 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ))
2065 goto out_error_tp;
2066
2067 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2068 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
2069 goto out_error_tp;
2070
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002071 if (trace->sched &&
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302072 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2073 trace__sched_stat_runtime))
2074 goto out_error_tp;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002075
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002076 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2077 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002078 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002079 goto out_delete_evlist;
2080 }
2081
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002082 err = trace__symbols_init(trace, evlist);
2083 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002084 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002085 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002086 }
2087
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002088 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002089
Namhyung Kimf15eb532012-10-05 14:02:16 +09002090 signal(SIGCHLD, sig_handler);
2091 signal(SIGINT, sig_handler);
2092
2093 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002094 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002095 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002096 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002097 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002098 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002099 }
2100 }
2101
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002102 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002103 if (err < 0)
2104 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002105
Jiri Olsaf8850372013-11-28 17:57:22 +01002106 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002107 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002108 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Arnaldo Carvalho de Melof26e1c72014-01-03 16:54:12 -03002109 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002110 }
2111
2112 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002113
2114 if (forks)
2115 perf_evlist__start_workload(evlist);
2116
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002117 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002118again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002119 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002120
2121 for (i = 0; i < evlist->nr_mmaps; i++) {
2122 union perf_event *event;
2123
2124 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
2125 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002126 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002127 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002128
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002129 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002130
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002131 err = perf_evlist__parse_sample(evlist, event, &sample);
2132 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002133 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002134 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002135 }
2136
David Ahern4bb09192013-09-04 12:37:43 -06002137 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002138 trace->base_time = sample.time;
2139
2140 if (type != PERF_RECORD_SAMPLE) {
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02002141 trace__process_event(trace, trace->host, event, &sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002142 continue;
2143 }
2144
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002145 evsel = perf_evlist__id2evsel(evlist, sample.id);
2146 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002147 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002148 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002149 }
2150
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002151 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2152 sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002153 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 -03002154 perf_evsel__name(evsel), sample.tid,
2155 sample.cpu, sample.raw_size);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002156 goto next_event;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002157 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002158
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002159 handler = evsel->handler;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002160 handler(trace, evsel, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002161next_event:
2162 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002163
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002164 if (interrupted)
2165 goto out_disable;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002166 }
2167 }
2168
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002169 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002170 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002171
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002172 if (poll(evlist->pollfd, evlist->nr_fds, timeout) > 0)
2173 goto again;
2174 } else {
2175 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002176 }
2177
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002178out_disable:
2179 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002180
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002181 if (!err) {
2182 if (trace->summary)
2183 trace__fprintf_thread_summary(trace, trace->output);
2184
2185 if (trace->show_tool_stats) {
2186 fprintf(trace->output, "Stats:\n "
2187 " vfs_getname : %" PRIu64 "\n"
2188 " proc_getname: %" PRIu64 "\n",
2189 trace->stats.vfs_getname,
2190 trace->stats.proc_getname);
2191 }
2192 }
David Ahernbf2575c2013-10-08 21:26:53 -06002193
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002194out_delete_evlist:
2195 perf_evlist__delete(evlist);
2196out:
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002197 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002198 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002199{
2200 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002201
2202out_error_tp:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002203 perf_evlist__strerror_tp(evlist, errno, errbuf, sizeof(errbuf));
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002204 goto out_error;
2205
2206out_error_open:
2207 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2208
2209out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002210 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302211 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002212}
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002213}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002214
David Ahern6810fc92013-08-28 22:29:52 -06002215static int trace__replay(struct trace *trace)
2216{
2217 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002218 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002219 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002220 struct perf_data_file file = {
2221 .path = input_name,
2222 .mode = PERF_DATA_MODE_READ,
2223 };
David Ahern6810fc92013-08-28 22:29:52 -06002224 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002225 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002226 int err = -1;
2227
2228 trace->tool.sample = trace__process_sample;
2229 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002230 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002231 trace->tool.comm = perf_event__process_comm;
2232 trace->tool.exit = perf_event__process_exit;
2233 trace->tool.fork = perf_event__process_fork;
2234 trace->tool.attr = perf_event__process_attr;
2235 trace->tool.tracing_data = perf_event__process_tracing_data;
2236 trace->tool.build_id = perf_event__process_build_id;
2237
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002238 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002239 trace->tool.ordering_requires_timestamps = true;
2240
2241 /* add tid to output */
2242 trace->multiple_threads = true;
2243
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002244 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002245 if (session == NULL)
2246 return -ENOMEM;
2247
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002248 if (symbol__init() < 0)
2249 goto out;
2250
David Ahern8fb598e2013-09-28 13:13:00 -06002251 trace->host = &session->machines.host;
2252
David Ahern6810fc92013-08-28 22:29:52 -06002253 err = perf_session__set_tracepoints_handlers(session, handlers);
2254 if (err)
2255 goto out;
2256
Namhyung Kim003824e2013-11-12 15:25:00 +09002257 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2258 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002259 /* older kernels have syscalls tp versus raw_syscalls */
2260 if (evsel == NULL)
2261 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2262 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002263
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002264 if (evsel &&
2265 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2266 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002267 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2268 goto out;
2269 }
2270
2271 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2272 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002273 if (evsel == NULL)
2274 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2275 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002276 if (evsel &&
2277 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2278 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002279 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002280 goto out;
2281 }
2282
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002283 evlist__for_each(session->evlist, evsel) {
2284 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2285 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2286 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2287 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2288 evsel->handler = trace__pgfault;
2289 }
2290
David Ahernbdc89662013-08-28 22:29:53 -06002291 err = parse_target_str(trace);
2292 if (err != 0)
2293 goto out;
2294
David Ahern6810fc92013-08-28 22:29:52 -06002295 setup_pager();
2296
2297 err = perf_session__process_events(session, &trace->tool);
2298 if (err)
2299 pr_err("Failed to process events, error %d", err);
2300
David Ahernbf2575c2013-10-08 21:26:53 -06002301 else if (trace->summary)
2302 trace__fprintf_thread_summary(trace, trace->output);
2303
David Ahern6810fc92013-08-28 22:29:52 -06002304out:
2305 perf_session__delete(session);
2306
2307 return err;
2308}
2309
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002310static size_t trace__fprintf_threads_header(FILE *fp)
2311{
2312 size_t printed;
2313
Pekka Enberg99ff7152013-11-12 16:42:14 +02002314 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002315
2316 return printed;
2317}
2318
2319static size_t thread__dump_stats(struct thread_trace *ttrace,
2320 struct trace *trace, FILE *fp)
2321{
2322 struct stats *stats;
2323 size_t printed = 0;
2324 struct syscall *sc;
2325 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2326
2327 if (inode == NULL)
2328 return 0;
2329
2330 printed += fprintf(fp, "\n");
2331
Pekka Enberg27a778b2013-11-13 14:21:48 +02002332 printed += fprintf(fp, " syscall calls min avg max stddev\n");
2333 printed += fprintf(fp, " (msec) (msec) (msec) (%%)\n");
2334 printed += fprintf(fp, " --------------- -------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002335
David Ahernbf2575c2013-10-08 21:26:53 -06002336 /* each int_node is a syscall */
2337 while (inode) {
2338 stats = inode->priv;
2339 if (stats) {
2340 double min = (double)(stats->min) / NSEC_PER_MSEC;
2341 double max = (double)(stats->max) / NSEC_PER_MSEC;
2342 double avg = avg_stats(stats);
2343 double pct;
2344 u64 n = (u64) stats->n;
2345
2346 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2347 avg /= NSEC_PER_MSEC;
2348
2349 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002350 printed += fprintf(fp, " %-15s", sc->name);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002351 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f",
Pekka Enberg7f7a4132013-11-12 16:10:10 +02002352 n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002353 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002354 }
2355
2356 inode = intlist__next(inode);
2357 }
2358
2359 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002360
2361 return printed;
2362}
2363
David Ahern896cbb52013-09-28 13:12:59 -06002364/* struct used to pass data to per-thread function */
2365struct summary_data {
2366 FILE *fp;
2367 struct trace *trace;
2368 size_t printed;
2369};
2370
2371static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2372{
2373 struct summary_data *data = priv;
2374 FILE *fp = data->fp;
2375 size_t printed = data->printed;
2376 struct trace *trace = data->trace;
2377 struct thread_trace *ttrace = thread->priv;
David Ahern896cbb52013-09-28 13:12:59 -06002378 double ratio;
2379
2380 if (ttrace == NULL)
2381 return 0;
2382
2383 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2384
Pekka Enberg15e65c62013-11-14 18:43:30 +02002385 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002386 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002387 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002388 if (ttrace->pfmaj)
2389 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2390 if (ttrace->pfmin)
2391 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002392 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002393 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002394
2395 data->printed += printed;
2396
2397 return 0;
2398}
2399
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002400static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2401{
David Ahern896cbb52013-09-28 13:12:59 -06002402 struct summary_data data = {
2403 .fp = fp,
2404 .trace = trace
2405 };
2406 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002407
David Ahern896cbb52013-09-28 13:12:59 -06002408 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002409
David Ahern896cbb52013-09-28 13:12:59 -06002410 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002411}
2412
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002413static int trace__set_duration(const struct option *opt, const char *str,
2414 int unset __maybe_unused)
2415{
2416 struct trace *trace = opt->value;
2417
2418 trace->duration_filter = atof(str);
2419 return 0;
2420}
2421
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002422static int trace__open_output(struct trace *trace, const char *filename)
2423{
2424 struct stat st;
2425
2426 if (!stat(filename, &st) && st.st_size) {
2427 char oldname[PATH_MAX];
2428
2429 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2430 unlink(oldname);
2431 rename(filename, oldname);
2432 }
2433
2434 trace->output = fopen(filename, "w");
2435
2436 return trace->output == NULL ? -errno : 0;
2437}
2438
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002439static int parse_pagefaults(const struct option *opt, const char *str,
2440 int unset __maybe_unused)
2441{
2442 int *trace_pgfaults = opt->value;
2443
2444 if (strcmp(str, "all") == 0)
2445 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2446 else if (strcmp(str, "maj") == 0)
2447 *trace_pgfaults |= TRACE_PFMAJ;
2448 else if (strcmp(str, "min") == 0)
2449 *trace_pgfaults |= TRACE_PFMIN;
2450 else
2451 return -1;
2452
2453 return 0;
2454}
2455
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002456int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2457{
2458 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002459 "perf trace [<options>] [<command>]",
2460 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002461 "perf trace record [<options>] [<command>]",
2462 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002463 NULL
2464 };
2465 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002466 .audit = {
2467 .machine = audit_detect_machine(),
2468 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2469 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002470 .syscalls = {
2471 . max = -1,
2472 },
2473 .opts = {
2474 .target = {
2475 .uid = UINT_MAX,
2476 .uses_mmap = true,
2477 },
2478 .user_freq = UINT_MAX,
2479 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002480 .no_buffering = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002481 .mmap_pages = 1024,
2482 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002483 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002484 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002485 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002486 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002487 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002488 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002489 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002490 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2491 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002492 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002493 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
2494 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002495 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002496 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002497 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2498 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002499 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002500 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002501 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002502 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002503 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002504 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002505 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002506 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002507 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2508 "number of mmap data pages",
2509 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002510 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002511 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002512 OPT_CALLBACK(0, "duration", &trace, "float",
2513 "show only events with duration > N.M ms",
2514 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002515 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002516 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002517 OPT_BOOLEAN('T', "time", &trace.full_time,
2518 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002519 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2520 "Show only syscall summary with statistics"),
2521 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2522 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002523 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2524 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002525 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002526 OPT_END()
2527 };
2528 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002529 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002530
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002531 argc = parse_options(argc, argv, trace_options, trace_usage,
2532 PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002533
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002534 if (trace.trace_pgfaults) {
2535 trace.opts.sample_address = true;
2536 trace.opts.sample_time = true;
2537 }
2538
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002539 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2540 return trace__record(&trace, argc-1, &argv[1]);
2541
2542 /* summary_only implies summary option, but don't overwrite summary if set */
2543 if (trace.summary_only)
2544 trace.summary = trace.summary_only;
2545
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002546 if (!trace.trace_syscalls && !trace.trace_pgfaults) {
2547 pr_err("Please specify something to trace.\n");
2548 return -1;
2549 }
2550
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002551 if (output_name != NULL) {
2552 err = trace__open_output(&trace, output_name);
2553 if (err < 0) {
2554 perror("failed to create output file");
2555 goto out;
2556 }
2557 }
2558
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002559 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002560 const char *s = ev_qualifier_str;
2561
2562 trace.not_ev_qualifier = *s == '!';
2563 if (trace.not_ev_qualifier)
2564 ++s;
2565 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002566 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002567 fputs("Not enough memory to parse event qualifier",
2568 trace.output);
2569 err = -ENOMEM;
2570 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002571 }
2572 }
2573
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002574 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002575 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002576 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002577 fprintf(trace.output, "%s", bf);
2578 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002579 }
2580
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002581 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002582 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002583 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002584 fprintf(trace.output, "%s", bf);
2585 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002586 }
2587
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002588 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002589 trace.opts.target.system_wide = true;
2590
David Ahern6810fc92013-08-28 22:29:52 -06002591 if (input_name)
2592 err = trace__replay(&trace);
2593 else
2594 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002595
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002596out_close:
2597 if (output_name != NULL)
2598 fclose(trace.output);
2599out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002600 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002601}