blob: badfabc6a01f6f1a90d1988abc5ac6178021bb08 [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
Namhyung Kim89dceb22014-10-06 09:46:03 +09001192 if (thread__priv(thread) == NULL)
1193 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001194
Namhyung Kim89dceb22014-10-06 09:46:03 +09001195 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001196 goto fail;
1197
Namhyung Kim89dceb22014-10-06 09:46:03 +09001198 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001199 ++ttrace->nr_events;
1200
1201 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001202fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001203 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001204 "WARNING: not enough memory, dropping samples!\n");
1205 return NULL;
1206}
1207
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001208#define TRACE_PFMAJ (1 << 0)
1209#define TRACE_PFMIN (1 << 1)
1210
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001211struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001212 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001213 struct {
1214 int machine;
1215 int open_id;
1216 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001217 struct {
1218 int max;
1219 struct syscall *table;
1220 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001221 struct record_opts opts;
David Ahern8fb598e2013-09-28 13:13:00 -06001222 struct machine *host;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001223 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001224 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001225 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001226 struct strlist *ev_qualifier;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001227 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -06001228 struct intlist *tid_list;
1229 struct intlist *pid_list;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001230 double duration_filter;
1231 double runtime_ms;
1232 struct {
1233 u64 vfs_getname,
1234 proc_getname;
1235 } stats;
1236 bool not_ev_qualifier;
1237 bool live;
1238 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001239 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001240 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001241 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001242 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001243 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001244 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001245 bool trace_syscalls;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001246 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001247};
1248
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001249static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001250{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001251 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001252
1253 if (fd > ttrace->paths.max) {
1254 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1255
1256 if (npath == NULL)
1257 return -1;
1258
1259 if (ttrace->paths.max != -1) {
1260 memset(npath + ttrace->paths.max + 1, 0,
1261 (fd - ttrace->paths.max) * sizeof(char *));
1262 } else {
1263 memset(npath, 0, (fd + 1) * sizeof(char *));
1264 }
1265
1266 ttrace->paths.table = npath;
1267 ttrace->paths.max = fd;
1268 }
1269
1270 ttrace->paths.table[fd] = strdup(pathname);
1271
1272 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1273}
1274
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001275static int thread__read_fd_path(struct thread *thread, int fd)
1276{
1277 char linkname[PATH_MAX], pathname[PATH_MAX];
1278 struct stat st;
1279 int ret;
1280
1281 if (thread->pid_ == thread->tid) {
1282 scnprintf(linkname, sizeof(linkname),
1283 "/proc/%d/fd/%d", thread->pid_, fd);
1284 } else {
1285 scnprintf(linkname, sizeof(linkname),
1286 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1287 }
1288
1289 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1290 return -1;
1291
1292 ret = readlink(linkname, pathname, sizeof(pathname));
1293
1294 if (ret < 0 || ret > st.st_size)
1295 return -1;
1296
1297 pathname[ret] = '\0';
1298 return trace__set_fd_pathname(thread, fd, pathname);
1299}
1300
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001301static const char *thread__fd_path(struct thread *thread, int fd,
1302 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001303{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001304 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001305
1306 if (ttrace == NULL)
1307 return NULL;
1308
1309 if (fd < 0)
1310 return NULL;
1311
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001312 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001313 if (!trace->live)
1314 return NULL;
1315 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001316 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001317 return NULL;
1318 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001319
1320 return ttrace->paths.table[fd];
1321}
1322
1323static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1324 struct syscall_arg *arg)
1325{
1326 int fd = arg->val;
1327 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001328 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001329
1330 if (path)
1331 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1332
1333 return printed;
1334}
1335
1336static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1337 struct syscall_arg *arg)
1338{
1339 int fd = arg->val;
1340 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001341 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001342
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001343 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1344 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001345
1346 return printed;
1347}
1348
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001349static bool trace__filter_duration(struct trace *trace, double t)
1350{
1351 return t < (trace->duration_filter * NSEC_PER_MSEC);
1352}
1353
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001354static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1355{
1356 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1357
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001358 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001359}
1360
Namhyung Kimf15eb532012-10-05 14:02:16 +09001361static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001362static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001363
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001364static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001365{
1366 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001367 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001368}
1369
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001370static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001371 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001372{
1373 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001374 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001375
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001376 if (trace->multiple_threads) {
1377 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001378 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001379 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001380 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001381
1382 return printed;
1383}
1384
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001385static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001386 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001387{
1388 int ret = 0;
1389
1390 switch (event->header.type) {
1391 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001392 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001393 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001394 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001395 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001396 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001397 break;
1398 }
1399
1400 return ret;
1401}
1402
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001403static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001404 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001405 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001406 struct machine *machine)
1407{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001408 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001409 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001410}
1411
1412static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1413{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001414 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001415
1416 if (err)
1417 return err;
1418
David Ahern8fb598e2013-09-28 13:13:00 -06001419 trace->host = machine__new_host();
1420 if (trace->host == NULL)
1421 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001422
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001423 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
1424 evlist->threads, trace__tool_process, false);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001425 if (err)
1426 symbol__exit();
1427
1428 return err;
1429}
1430
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001431static int syscall__set_arg_fmts(struct syscall *sc)
1432{
1433 struct format_field *field;
1434 int idx = 0;
1435
1436 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1437 if (sc->arg_scnprintf == NULL)
1438 return -1;
1439
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001440 if (sc->fmt)
1441 sc->arg_parm = sc->fmt->arg_parm;
1442
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001443 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001444 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1445 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1446 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001447 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1448 ++idx;
1449 }
1450
1451 return 0;
1452}
1453
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001454static int trace__read_syscall_info(struct trace *trace, int id)
1455{
1456 char tp_name[128];
1457 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001458 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001459
1460 if (name == NULL)
1461 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001462
1463 if (id > trace->syscalls.max) {
1464 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1465
1466 if (nsyscalls == NULL)
1467 return -1;
1468
1469 if (trace->syscalls.max != -1) {
1470 memset(nsyscalls + trace->syscalls.max + 1, 0,
1471 (id - trace->syscalls.max) * sizeof(*sc));
1472 } else {
1473 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1474 }
1475
1476 trace->syscalls.table = nsyscalls;
1477 trace->syscalls.max = id;
1478 }
1479
1480 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001481 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001482
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001483 if (trace->ev_qualifier) {
1484 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1485
1486 if (!(in ^ trace->not_ev_qualifier)) {
1487 sc->filtered = true;
1488 /*
1489 * No need to do read tracepoint information since this will be
1490 * filtered out.
1491 */
1492 return 0;
1493 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001494 }
1495
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001496 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001497
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001498 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001499 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001500
1501 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1502 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001503 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001504 }
1505
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001506 if (sc->tp_format == NULL)
1507 return -1;
1508
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001509 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1510
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001511 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001512}
1513
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001514static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001515 unsigned long *args, struct trace *trace,
1516 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001517{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001518 size_t printed = 0;
1519
1520 if (sc->tp_format != NULL) {
1521 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001522 u8 bit = 1;
1523 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001524 .idx = 0,
1525 .mask = 0,
1526 .trace = trace,
1527 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001528 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001529
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001530 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001531 field = field->next, ++arg.idx, bit <<= 1) {
1532 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001533 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001534 /*
1535 * Suppress this argument if its value is zero and
1536 * and we don't have a string associated in an
1537 * strarray for it.
1538 */
1539 if (args[arg.idx] == 0 &&
1540 !(sc->arg_scnprintf &&
1541 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1542 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001543 continue;
1544
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001545 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001546 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001547 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1548 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001549 if (sc->arg_parm)
1550 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001551 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1552 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001553 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001554 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001555 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001556 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001557 }
1558 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001559 int i = 0;
1560
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001561 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001562 printed += scnprintf(bf + printed, size - printed,
1563 "%sarg%d: %ld",
1564 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001565 ++i;
1566 }
1567 }
1568
1569 return printed;
1570}
1571
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001572typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001573 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001574 struct perf_sample *sample);
1575
1576static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001577 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001578{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001579
1580 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001581
1582 /*
1583 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1584 * before that, leaving at a higher verbosity level till that is
1585 * explained. Reproduced with plain ftrace with:
1586 *
1587 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1588 * grep "NR -1 " /t/trace_pipe
1589 *
1590 * After generating some load on the machine.
1591 */
1592 if (verbose > 1) {
1593 static u64 n;
1594 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1595 id, perf_evsel__name(evsel), ++n);
1596 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001597 return NULL;
1598 }
1599
1600 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1601 trace__read_syscall_info(trace, id))
1602 goto out_cant_read;
1603
1604 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1605 goto out_cant_read;
1606
1607 return &trace->syscalls.table[id];
1608
1609out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001610 if (verbose) {
1611 fprintf(trace->output, "Problems reading syscall %d", id);
1612 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1613 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1614 fputs(" information\n", trace->output);
1615 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001616 return NULL;
1617}
1618
David Ahernbf2575c2013-10-08 21:26:53 -06001619static void thread__update_stats(struct thread_trace *ttrace,
1620 int id, struct perf_sample *sample)
1621{
1622 struct int_node *inode;
1623 struct stats *stats;
1624 u64 duration = 0;
1625
1626 inode = intlist__findnew(ttrace->syscall_stats, id);
1627 if (inode == NULL)
1628 return;
1629
1630 stats = inode->priv;
1631 if (stats == NULL) {
1632 stats = malloc(sizeof(struct stats));
1633 if (stats == NULL)
1634 return;
1635 init_stats(stats);
1636 inode->priv = stats;
1637 }
1638
1639 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1640 duration = sample->time - ttrace->entry_time;
1641
1642 update_stats(stats, duration);
1643}
1644
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001645static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001646 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001647 struct perf_sample *sample)
1648{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001649 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001650 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001651 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001652 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001653 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001654 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001655 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001656
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001657 if (sc == NULL)
1658 return -1;
1659
1660 if (sc->filtered)
1661 return 0;
1662
David Ahern8fb598e2013-09-28 13:13:00 -06001663 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001664 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001665 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001666 return -1;
1667
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001668 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001669
1670 if (ttrace->entry_str == NULL) {
1671 ttrace->entry_str = malloc(1024);
1672 if (!ttrace->entry_str)
1673 return -1;
1674 }
1675
1676 ttrace->entry_time = sample->time;
1677 msg = ttrace->entry_str;
1678 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1679
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001680 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1681 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001682
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001683 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001684 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001685 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1686 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001687 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001688 } else
1689 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001690
1691 return 0;
1692}
1693
1694static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001695 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001696 struct perf_sample *sample)
1697{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001698 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001699 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001700 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001701 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001702 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001703 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001704
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001705 if (sc == NULL)
1706 return -1;
1707
1708 if (sc->filtered)
1709 return 0;
1710
David Ahern8fb598e2013-09-28 13:13:00 -06001711 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001712 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001713 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001714 return -1;
1715
David Ahernbf2575c2013-10-08 21:26:53 -06001716 if (trace->summary)
1717 thread__update_stats(ttrace, id, sample);
1718
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001719 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001720
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001721 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1722 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1723 trace->last_vfs_getname = NULL;
1724 ++trace->stats.vfs_getname;
1725 }
1726
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001727 ttrace->exit_time = sample->time;
1728
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001729 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001730 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001731 if (trace__filter_duration(trace, duration))
1732 goto out;
1733 } else if (trace->duration_filter)
1734 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001735
David Ahernfd2eaba2013-11-12 09:31:15 -07001736 if (trace->summary_only)
1737 goto out;
1738
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001739 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001740
1741 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001742 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001743 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001744 fprintf(trace->output, " ... [");
1745 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1746 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001747 }
1748
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001749 if (sc->fmt == NULL) {
1750signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001751 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001752 } else if (ret < 0 && sc->fmt->errmsg) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001753 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001754 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1755 *e = audit_errno_to_name(-ret);
1756
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001757 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001758 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001759 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001760 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001761 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001762 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001763 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001764
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001765 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001766out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001767 ttrace->entry_pending = false;
1768
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001769 return 0;
1770}
1771
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001772static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001773 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001774 struct perf_sample *sample)
1775{
1776 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1777 return 0;
1778}
1779
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001780static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001781 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001782 struct perf_sample *sample)
1783{
1784 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1785 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001786 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001787 sample->pid,
1788 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001789 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001790
1791 if (ttrace == NULL)
1792 goto out_dump;
1793
1794 ttrace->runtime_ms += runtime_ms;
1795 trace->runtime_ms += runtime_ms;
1796 return 0;
1797
1798out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001799 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001800 evsel->name,
1801 perf_evsel__strval(evsel, sample, "comm"),
1802 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1803 runtime,
1804 perf_evsel__intval(evsel, sample, "vruntime"));
1805 return 0;
1806}
1807
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001808static void print_location(FILE *f, struct perf_sample *sample,
1809 struct addr_location *al,
1810 bool print_dso, bool print_sym)
1811{
1812
1813 if ((verbose || print_dso) && al->map)
1814 fprintf(f, "%s@", al->map->dso->long_name);
1815
1816 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001817 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001818 al->addr - al->sym->start);
1819 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001820 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001821 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001822 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001823}
1824
1825static int trace__pgfault(struct trace *trace,
1826 struct perf_evsel *evsel,
1827 union perf_event *event,
1828 struct perf_sample *sample)
1829{
1830 struct thread *thread;
1831 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1832 struct addr_location al;
1833 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001834 struct thread_trace *ttrace;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001835
1836 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001837 ttrace = thread__trace(thread, trace->output);
1838 if (ttrace == NULL)
1839 return -1;
1840
1841 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1842 ttrace->pfmaj++;
1843 else
1844 ttrace->pfmin++;
1845
1846 if (trace->summary_only)
1847 return 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001848
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03001849 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001850 sample->ip, &al);
1851
1852 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
1853
1854 fprintf(trace->output, "%sfault [",
1855 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1856 "maj" : "min");
1857
1858 print_location(trace->output, sample, &al, false, true);
1859
1860 fprintf(trace->output, "] => ");
1861
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03001862 thread__find_addr_location(thread, cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001863 sample->addr, &al);
1864
1865 if (!al.map) {
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03001866 thread__find_addr_location(thread, cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001867 MAP__FUNCTION, sample->addr, &al);
1868
1869 if (al.map)
1870 map_type = 'x';
1871 else
1872 map_type = '?';
1873 }
1874
1875 print_location(trace->output, sample, &al, true, false);
1876
1877 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
1878
1879 return 0;
1880}
1881
David Ahernbdc89662013-08-28 22:29:53 -06001882static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1883{
1884 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1885 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1886 return false;
1887
1888 if (trace->pid_list || trace->tid_list)
1889 return true;
1890
1891 return false;
1892}
1893
David Ahern6810fc92013-08-28 22:29:52 -06001894static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001895 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001896 struct perf_sample *sample,
1897 struct perf_evsel *evsel,
1898 struct machine *machine __maybe_unused)
1899{
1900 struct trace *trace = container_of(tool, struct trace, tool);
1901 int err = 0;
1902
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001903 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001904
David Ahernbdc89662013-08-28 22:29:53 -06001905 if (skip_sample(trace, sample))
1906 return 0;
1907
David Ahern4bb09192013-09-04 12:37:43 -06001908 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001909 trace->base_time = sample->time;
1910
David Ahern31605652013-12-04 19:41:41 -07001911 if (handler) {
1912 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001913 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07001914 }
David Ahern6810fc92013-08-28 22:29:52 -06001915
1916 return err;
1917}
1918
David Ahernbdc89662013-08-28 22:29:53 -06001919static int parse_target_str(struct trace *trace)
1920{
1921 if (trace->opts.target.pid) {
1922 trace->pid_list = intlist__new(trace->opts.target.pid);
1923 if (trace->pid_list == NULL) {
1924 pr_err("Error parsing process id string\n");
1925 return -EINVAL;
1926 }
1927 }
1928
1929 if (trace->opts.target.tid) {
1930 trace->tid_list = intlist__new(trace->opts.target.tid);
1931 if (trace->tid_list == NULL) {
1932 pr_err("Error parsing thread id string\n");
1933 return -EINVAL;
1934 }
1935 }
1936
1937 return 0;
1938}
1939
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001940static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06001941{
1942 unsigned int rec_argc, i, j;
1943 const char **rec_argv;
1944 const char * const record_args[] = {
1945 "record",
1946 "-R",
1947 "-m", "1024",
1948 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06001949 };
1950
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001951 const char * const sc_args[] = { "-e", };
1952 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
1953 const char * const majpf_args[] = { "-e", "major-faults" };
1954 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
1955 const char * const minpf_args[] = { "-e", "minor-faults" };
1956 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
1957
David Ahern9aca7f12013-12-04 19:41:39 -07001958 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001959 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
1960 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06001961 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1962
1963 if (rec_argv == NULL)
1964 return -ENOMEM;
1965
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001966 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06001967 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001968 rec_argv[j++] = record_args[i];
1969
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001970 if (trace->trace_syscalls) {
1971 for (i = 0; i < sc_args_nr; i++)
1972 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06001973
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001974 /* event string may be different for older kernels - e.g., RHEL6 */
1975 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
1976 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
1977 else if (is_valid_tracepoint("syscalls:sys_enter"))
1978 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
1979 else {
1980 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
1981 return -1;
1982 }
David Ahern9aca7f12013-12-04 19:41:39 -07001983 }
David Ahern9aca7f12013-12-04 19:41:39 -07001984
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001985 if (trace->trace_pgfaults & TRACE_PFMAJ)
1986 for (i = 0; i < majpf_args_nr; i++)
1987 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06001988
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001989 if (trace->trace_pgfaults & TRACE_PFMIN)
1990 for (i = 0; i < minpf_args_nr; i++)
1991 rec_argv[j++] = minpf_args[i];
1992
1993 for (i = 0; i < (unsigned int)argc; i++)
1994 rec_argv[j++] = argv[i];
1995
1996 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06001997}
1998
David Ahernbf2575c2013-10-08 21:26:53 -06001999static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2000
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002001static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
2002{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002003 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002004 if (evsel == NULL)
2005 return;
2006
2007 if (perf_evsel__field(evsel, "pathname") == NULL) {
2008 perf_evsel__delete(evsel);
2009 return;
2010 }
2011
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002012 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002013 perf_evlist__add(evlist, evsel);
2014}
2015
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002016static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2017 u64 config)
2018{
2019 struct perf_evsel *evsel;
2020 struct perf_event_attr attr = {
2021 .type = PERF_TYPE_SOFTWARE,
2022 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002023 };
2024
2025 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002026 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002027
2028 event_attr_init(&attr);
2029
2030 evsel = perf_evsel__new(&attr);
2031 if (!evsel)
2032 return -ENOMEM;
2033
2034 evsel->handler = trace__pgfault;
2035 perf_evlist__add(evlist, evsel);
2036
2037 return 0;
2038}
2039
Namhyung Kimf15eb532012-10-05 14:02:16 +09002040static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002041{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09002042 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002043 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002044 int err = -1, i;
2045 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002046 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002047 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002048
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002049 trace->live = true;
2050
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002051 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002052 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002053 goto out;
2054 }
2055
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002056 if (trace->trace_syscalls &&
2057 perf_evlist__add_syscall_newtp(evlist, trace__sys_enter,
2058 trace__sys_exit))
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302059 goto out_error_tp;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002060
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002061 if (trace->trace_syscalls)
2062 perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002063
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002064 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
2065 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ))
2066 goto out_error_tp;
2067
2068 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2069 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
2070 goto out_error_tp;
2071
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002072 if (trace->sched &&
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302073 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2074 trace__sched_stat_runtime))
2075 goto out_error_tp;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002076
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002077 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2078 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002079 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002080 goto out_delete_evlist;
2081 }
2082
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002083 err = trace__symbols_init(trace, evlist);
2084 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002085 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002086 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002087 }
2088
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002089 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002090
Namhyung Kimf15eb532012-10-05 14:02:16 +09002091 signal(SIGCHLD, sig_handler);
2092 signal(SIGINT, sig_handler);
2093
2094 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002095 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002096 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002097 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002098 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002099 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002100 }
2101 }
2102
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002103 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002104 if (err < 0)
2105 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002106
Jiri Olsaf8850372013-11-28 17:57:22 +01002107 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002108 if (err < 0)
2109 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002110
2111 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002112
2113 if (forks)
2114 perf_evlist__start_workload(evlist);
2115
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002116 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002117again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002118 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002119
2120 for (i = 0; i < evlist->nr_mmaps; i++) {
2121 union perf_event *event;
2122
2123 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
2124 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002125 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002126 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002127
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002128 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002129
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002130 err = perf_evlist__parse_sample(evlist, event, &sample);
2131 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002132 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002133 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002134 }
2135
David Ahern4bb09192013-09-04 12:37:43 -06002136 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002137 trace->base_time = sample.time;
2138
2139 if (type != PERF_RECORD_SAMPLE) {
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02002140 trace__process_event(trace, trace->host, event, &sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002141 continue;
2142 }
2143
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002144 evsel = perf_evlist__id2evsel(evlist, sample.id);
2145 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002146 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002147 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002148 }
2149
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002150 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2151 sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002152 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 -03002153 perf_evsel__name(evsel), sample.tid,
2154 sample.cpu, sample.raw_size);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002155 goto next_event;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002156 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002157
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002158 handler = evsel->handler;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002159 handler(trace, evsel, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002160next_event:
2161 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002162
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002163 if (interrupted)
2164 goto out_disable;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002165 }
2166 }
2167
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002168 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002169 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002170
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002171 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2172 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2173 draining = true;
2174
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002175 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002176 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002177 } else {
2178 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002179 }
2180
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002181out_disable:
2182 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002183
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002184 if (!err) {
2185 if (trace->summary)
2186 trace__fprintf_thread_summary(trace, trace->output);
2187
2188 if (trace->show_tool_stats) {
2189 fprintf(trace->output, "Stats:\n "
2190 " vfs_getname : %" PRIu64 "\n"
2191 " proc_getname: %" PRIu64 "\n",
2192 trace->stats.vfs_getname,
2193 trace->stats.proc_getname);
2194 }
2195 }
David Ahernbf2575c2013-10-08 21:26:53 -06002196
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002197out_delete_evlist:
2198 perf_evlist__delete(evlist);
2199out:
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002200 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002201 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002202{
2203 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002204
2205out_error_tp:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002206 perf_evlist__strerror_tp(evlist, errno, errbuf, sizeof(errbuf));
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002207 goto out_error;
2208
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002209out_error_mmap:
2210 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2211 goto out_error;
2212
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002213out_error_open:
2214 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2215
2216out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002217 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302218 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002219}
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002220}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002221
David Ahern6810fc92013-08-28 22:29:52 -06002222static int trace__replay(struct trace *trace)
2223{
2224 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002225 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002226 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002227 struct perf_data_file file = {
2228 .path = input_name,
2229 .mode = PERF_DATA_MODE_READ,
2230 };
David Ahern6810fc92013-08-28 22:29:52 -06002231 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002232 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002233 int err = -1;
2234
2235 trace->tool.sample = trace__process_sample;
2236 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002237 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002238 trace->tool.comm = perf_event__process_comm;
2239 trace->tool.exit = perf_event__process_exit;
2240 trace->tool.fork = perf_event__process_fork;
2241 trace->tool.attr = perf_event__process_attr;
2242 trace->tool.tracing_data = perf_event__process_tracing_data;
2243 trace->tool.build_id = perf_event__process_build_id;
2244
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002245 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002246 trace->tool.ordering_requires_timestamps = true;
2247
2248 /* add tid to output */
2249 trace->multiple_threads = true;
2250
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002251 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002252 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002253 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002254
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002255 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002256 goto out;
2257
David Ahern8fb598e2013-09-28 13:13:00 -06002258 trace->host = &session->machines.host;
2259
David Ahern6810fc92013-08-28 22:29:52 -06002260 err = perf_session__set_tracepoints_handlers(session, handlers);
2261 if (err)
2262 goto out;
2263
Namhyung Kim003824e2013-11-12 15:25:00 +09002264 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2265 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002266 /* older kernels have syscalls tp versus raw_syscalls */
2267 if (evsel == NULL)
2268 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2269 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002270
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002271 if (evsel &&
2272 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2273 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002274 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2275 goto out;
2276 }
2277
2278 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2279 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002280 if (evsel == NULL)
2281 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2282 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002283 if (evsel &&
2284 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2285 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002286 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002287 goto out;
2288 }
2289
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002290 evlist__for_each(session->evlist, evsel) {
2291 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2292 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2293 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2294 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2295 evsel->handler = trace__pgfault;
2296 }
2297
David Ahernbdc89662013-08-28 22:29:53 -06002298 err = parse_target_str(trace);
2299 if (err != 0)
2300 goto out;
2301
David Ahern6810fc92013-08-28 22:29:52 -06002302 setup_pager();
2303
2304 err = perf_session__process_events(session, &trace->tool);
2305 if (err)
2306 pr_err("Failed to process events, error %d", err);
2307
David Ahernbf2575c2013-10-08 21:26:53 -06002308 else if (trace->summary)
2309 trace__fprintf_thread_summary(trace, trace->output);
2310
David Ahern6810fc92013-08-28 22:29:52 -06002311out:
2312 perf_session__delete(session);
2313
2314 return err;
2315}
2316
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002317static size_t trace__fprintf_threads_header(FILE *fp)
2318{
2319 size_t printed;
2320
Pekka Enberg99ff7152013-11-12 16:42:14 +02002321 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002322
2323 return printed;
2324}
2325
2326static size_t thread__dump_stats(struct thread_trace *ttrace,
2327 struct trace *trace, FILE *fp)
2328{
2329 struct stats *stats;
2330 size_t printed = 0;
2331 struct syscall *sc;
2332 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2333
2334 if (inode == NULL)
2335 return 0;
2336
2337 printed += fprintf(fp, "\n");
2338
Pekka Enberg27a778b2013-11-13 14:21:48 +02002339 printed += fprintf(fp, " syscall calls min avg max stddev\n");
2340 printed += fprintf(fp, " (msec) (msec) (msec) (%%)\n");
2341 printed += fprintf(fp, " --------------- -------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002342
David Ahernbf2575c2013-10-08 21:26:53 -06002343 /* each int_node is a syscall */
2344 while (inode) {
2345 stats = inode->priv;
2346 if (stats) {
2347 double min = (double)(stats->min) / NSEC_PER_MSEC;
2348 double max = (double)(stats->max) / NSEC_PER_MSEC;
2349 double avg = avg_stats(stats);
2350 double pct;
2351 u64 n = (u64) stats->n;
2352
2353 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2354 avg /= NSEC_PER_MSEC;
2355
2356 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002357 printed += fprintf(fp, " %-15s", sc->name);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002358 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f",
Pekka Enberg7f7a4132013-11-12 16:10:10 +02002359 n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002360 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002361 }
2362
2363 inode = intlist__next(inode);
2364 }
2365
2366 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002367
2368 return printed;
2369}
2370
David Ahern896cbb52013-09-28 13:12:59 -06002371/* struct used to pass data to per-thread function */
2372struct summary_data {
2373 FILE *fp;
2374 struct trace *trace;
2375 size_t printed;
2376};
2377
2378static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2379{
2380 struct summary_data *data = priv;
2381 FILE *fp = data->fp;
2382 size_t printed = data->printed;
2383 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002384 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002385 double ratio;
2386
2387 if (ttrace == NULL)
2388 return 0;
2389
2390 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2391
Pekka Enberg15e65c62013-11-14 18:43:30 +02002392 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002393 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002394 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002395 if (ttrace->pfmaj)
2396 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2397 if (ttrace->pfmin)
2398 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002399 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002400 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002401
2402 data->printed += printed;
2403
2404 return 0;
2405}
2406
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002407static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2408{
David Ahern896cbb52013-09-28 13:12:59 -06002409 struct summary_data data = {
2410 .fp = fp,
2411 .trace = trace
2412 };
2413 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002414
David Ahern896cbb52013-09-28 13:12:59 -06002415 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002416
David Ahern896cbb52013-09-28 13:12:59 -06002417 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002418}
2419
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002420static int trace__set_duration(const struct option *opt, const char *str,
2421 int unset __maybe_unused)
2422{
2423 struct trace *trace = opt->value;
2424
2425 trace->duration_filter = atof(str);
2426 return 0;
2427}
2428
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002429static int trace__open_output(struct trace *trace, const char *filename)
2430{
2431 struct stat st;
2432
2433 if (!stat(filename, &st) && st.st_size) {
2434 char oldname[PATH_MAX];
2435
2436 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2437 unlink(oldname);
2438 rename(filename, oldname);
2439 }
2440
2441 trace->output = fopen(filename, "w");
2442
2443 return trace->output == NULL ? -errno : 0;
2444}
2445
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002446static int parse_pagefaults(const struct option *opt, const char *str,
2447 int unset __maybe_unused)
2448{
2449 int *trace_pgfaults = opt->value;
2450
2451 if (strcmp(str, "all") == 0)
2452 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2453 else if (strcmp(str, "maj") == 0)
2454 *trace_pgfaults |= TRACE_PFMAJ;
2455 else if (strcmp(str, "min") == 0)
2456 *trace_pgfaults |= TRACE_PFMIN;
2457 else
2458 return -1;
2459
2460 return 0;
2461}
2462
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002463int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2464{
2465 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002466 "perf trace [<options>] [<command>]",
2467 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002468 "perf trace record [<options>] [<command>]",
2469 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002470 NULL
2471 };
2472 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002473 .audit = {
2474 .machine = audit_detect_machine(),
2475 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2476 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002477 .syscalls = {
2478 . max = -1,
2479 },
2480 .opts = {
2481 .target = {
2482 .uid = UINT_MAX,
2483 .uses_mmap = true,
2484 },
2485 .user_freq = UINT_MAX,
2486 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002487 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002488 .mmap_pages = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002489 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002490 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002491 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002492 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002493 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002494 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002495 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002496 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002497 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2498 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002499 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002500 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
2501 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002502 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002503 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002504 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2505 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002506 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002507 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002508 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002509 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002510 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002511 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002512 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002513 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002514 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2515 "number of mmap data pages",
2516 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002517 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002518 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002519 OPT_CALLBACK(0, "duration", &trace, "float",
2520 "show only events with duration > N.M ms",
2521 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002522 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002523 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002524 OPT_BOOLEAN('T', "time", &trace.full_time,
2525 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002526 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2527 "Show only syscall summary with statistics"),
2528 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2529 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002530 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2531 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002532 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002533 OPT_END()
2534 };
2535 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002536 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002537
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002538 argc = parse_options(argc, argv, trace_options, trace_usage,
2539 PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002540
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002541 if (trace.trace_pgfaults) {
2542 trace.opts.sample_address = true;
2543 trace.opts.sample_time = true;
2544 }
2545
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002546 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2547 return trace__record(&trace, argc-1, &argv[1]);
2548
2549 /* summary_only implies summary option, but don't overwrite summary if set */
2550 if (trace.summary_only)
2551 trace.summary = trace.summary_only;
2552
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002553 if (!trace.trace_syscalls && !trace.trace_pgfaults) {
2554 pr_err("Please specify something to trace.\n");
2555 return -1;
2556 }
2557
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002558 if (output_name != NULL) {
2559 err = trace__open_output(&trace, output_name);
2560 if (err < 0) {
2561 perror("failed to create output file");
2562 goto out;
2563 }
2564 }
2565
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002566 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002567 const char *s = ev_qualifier_str;
2568
2569 trace.not_ev_qualifier = *s == '!';
2570 if (trace.not_ev_qualifier)
2571 ++s;
2572 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002573 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002574 fputs("Not enough memory to parse event qualifier",
2575 trace.output);
2576 err = -ENOMEM;
2577 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002578 }
2579 }
2580
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002581 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002582 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;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002586 }
2587
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002588 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002589 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002590 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002591 fprintf(trace.output, "%s", bf);
2592 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002593 }
2594
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002595 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002596 trace.opts.target.system_wide = true;
2597
David Ahern6810fc92013-08-28 22:29:52 -06002598 if (input_name)
2599 err = trace__replay(&trace);
2600 else
2601 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002602
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002603out_close:
2604 if (output_name != NULL)
2605 fclose(trace.output);
2606out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002607 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002608}