blob: a7aa771a98e625c70258db1c44b5ee911b5aa16d [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
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -030040struct tp_field {
41 int offset;
42 union {
43 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
44 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
45 };
46};
47
48#define TP_UINT_FIELD(bits) \
49static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
50{ \
51 return *(u##bits *)(sample->raw_data + field->offset); \
52}
53
54TP_UINT_FIELD(8);
55TP_UINT_FIELD(16);
56TP_UINT_FIELD(32);
57TP_UINT_FIELD(64);
58
59#define TP_UINT_FIELD__SWAPPED(bits) \
60static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
61{ \
62 u##bits value = *(u##bits *)(sample->raw_data + field->offset); \
63 return bswap_##bits(value);\
64}
65
66TP_UINT_FIELD__SWAPPED(16);
67TP_UINT_FIELD__SWAPPED(32);
68TP_UINT_FIELD__SWAPPED(64);
69
70static int tp_field__init_uint(struct tp_field *field,
71 struct format_field *format_field,
72 bool needs_swap)
73{
74 field->offset = format_field->offset;
75
76 switch (format_field->size) {
77 case 1:
78 field->integer = tp_field__u8;
79 break;
80 case 2:
81 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
82 break;
83 case 4:
84 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
85 break;
86 case 8:
87 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
88 break;
89 default:
90 return -1;
91 }
92
93 return 0;
94}
95
96static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
97{
98 return sample->raw_data + field->offset;
99}
100
101static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
102{
103 field->offset = format_field->offset;
104 field->pointer = tp_field__ptr;
105 return 0;
106}
107
108struct syscall_tp {
109 struct tp_field id;
110 union {
111 struct tp_field args, ret;
112 };
113};
114
115static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
116 struct tp_field *field,
117 const char *name)
118{
119 struct format_field *format_field = perf_evsel__field(evsel, name);
120
121 if (format_field == NULL)
122 return -1;
123
124 return tp_field__init_uint(field, format_field, evsel->needs_swap);
125}
126
127#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
128 ({ struct syscall_tp *sc = evsel->priv;\
129 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
130
131static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
132 struct tp_field *field,
133 const char *name)
134{
135 struct format_field *format_field = perf_evsel__field(evsel, name);
136
137 if (format_field == NULL)
138 return -1;
139
140 return tp_field__init_ptr(field, format_field);
141}
142
143#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
144 ({ struct syscall_tp *sc = evsel->priv;\
145 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
146
147static void perf_evsel__delete_priv(struct perf_evsel *evsel)
148{
149 free(evsel->priv);
150 evsel->priv = NULL;
151 perf_evsel__delete(evsel);
152}
153
Namhyung Kim96695d42013-11-12 08:51:45 -0300154static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
155{
156 evsel->priv = malloc(sizeof(struct syscall_tp));
157 if (evsel->priv != NULL) {
158 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
159 goto out_delete;
160
161 evsel->handler = handler;
162 return 0;
163 }
164
165 return -ENOMEM;
166
167out_delete:
168 free(evsel->priv);
169 evsel->priv = NULL;
170 return -ENOENT;
171}
172
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300173static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300174{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300175 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300176
David Ahern9aca7f12013-12-04 19:41:39 -0700177 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
178 if (evsel == NULL)
179 evsel = perf_evsel__newtp("syscalls", direction);
180
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300181 if (evsel) {
Namhyung Kim96695d42013-11-12 08:51:45 -0300182 if (perf_evsel__init_syscall_tp(evsel, handler))
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300183 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300184 }
185
186 return evsel;
187
188out_delete:
189 perf_evsel__delete_priv(evsel);
190 return NULL;
191}
192
193#define perf_evsel__sc_tp_uint(evsel, name, sample) \
194 ({ struct syscall_tp *fields = evsel->priv; \
195 fields->name.integer(&fields->name, sample); })
196
197#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
198 ({ struct syscall_tp *fields = evsel->priv; \
199 fields->name.pointer(&fields->name, sample); })
200
201static int perf_evlist__add_syscall_newtp(struct perf_evlist *evlist,
202 void *sys_enter_handler,
203 void *sys_exit_handler)
204{
205 int ret = -1;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300206 struct perf_evsel *sys_enter, *sys_exit;
207
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300208 sys_enter = perf_evsel__syscall_newtp("sys_enter", sys_enter_handler);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300209 if (sys_enter == NULL)
210 goto out;
211
212 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
213 goto out_delete_sys_enter;
214
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300215 sys_exit = perf_evsel__syscall_newtp("sys_exit", sys_exit_handler);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300216 if (sys_exit == NULL)
217 goto out_delete_sys_enter;
218
219 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
220 goto out_delete_sys_exit;
221
222 perf_evlist__add(evlist, sys_enter);
223 perf_evlist__add(evlist, sys_exit);
224
225 ret = 0;
226out:
227 return ret;
228
229out_delete_sys_exit:
230 perf_evsel__delete_priv(sys_exit);
231out_delete_sys_enter:
232 perf_evsel__delete_priv(sys_enter);
233 goto out;
234}
235
236
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300237struct syscall_arg {
238 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300239 struct thread *thread;
240 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300241 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300242 u8 idx;
243 u8 mask;
244};
245
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300246struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300247 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300248 int nr_entries;
249 const char **entries;
250};
251
252#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
253 .nr_entries = ARRAY_SIZE(array), \
254 .entries = array, \
255}
256
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300257#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
258 .offset = off, \
259 .nr_entries = ARRAY_SIZE(array), \
260 .entries = array, \
261}
262
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300263static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
264 const char *intfmt,
265 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300266{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300267 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300268 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300269
270 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300271 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300272
273 return scnprintf(bf, size, "%s", sa->entries[idx]);
274}
275
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300276static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
277 struct syscall_arg *arg)
278{
279 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
280}
281
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300282#define SCA_STRARRAY syscall_arg__scnprintf_strarray
283
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300284static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
285 struct syscall_arg *arg)
286{
287 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
288}
289
290#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
291
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300292static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
293 struct syscall_arg *arg);
294
295#define SCA_FD syscall_arg__scnprintf_fd
296
297static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
298 struct syscall_arg *arg)
299{
300 int fd = arg->val;
301
302 if (fd == AT_FDCWD)
303 return scnprintf(bf, size, "CWD");
304
305 return syscall_arg__scnprintf_fd(bf, size, arg);
306}
307
308#define SCA_FDAT syscall_arg__scnprintf_fd_at
309
310static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
311 struct syscall_arg *arg);
312
313#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
314
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300315static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300316 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300317{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300318 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300319}
320
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300321#define SCA_HEX syscall_arg__scnprintf_hex
322
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300323static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300324 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300325{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300326 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300327
328 if (prot == PROT_NONE)
329 return scnprintf(bf, size, "NONE");
330#define P_MMAP_PROT(n) \
331 if (prot & PROT_##n) { \
332 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
333 prot &= ~PROT_##n; \
334 }
335
336 P_MMAP_PROT(EXEC);
337 P_MMAP_PROT(READ);
338 P_MMAP_PROT(WRITE);
339#ifdef PROT_SEM
340 P_MMAP_PROT(SEM);
341#endif
342 P_MMAP_PROT(GROWSDOWN);
343 P_MMAP_PROT(GROWSUP);
344#undef P_MMAP_PROT
345
346 if (prot)
347 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
348
349 return printed;
350}
351
352#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
353
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300354static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300355 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300356{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300357 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300358
359#define P_MMAP_FLAG(n) \
360 if (flags & MAP_##n) { \
361 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
362 flags &= ~MAP_##n; \
363 }
364
365 P_MMAP_FLAG(SHARED);
366 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400367#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300368 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400369#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300370 P_MMAP_FLAG(ANONYMOUS);
371 P_MMAP_FLAG(DENYWRITE);
372 P_MMAP_FLAG(EXECUTABLE);
373 P_MMAP_FLAG(FILE);
374 P_MMAP_FLAG(FIXED);
375 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600376#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300377 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600378#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300379 P_MMAP_FLAG(LOCKED);
380 P_MMAP_FLAG(NONBLOCK);
381 P_MMAP_FLAG(NORESERVE);
382 P_MMAP_FLAG(POPULATE);
383 P_MMAP_FLAG(STACK);
384#ifdef MAP_UNINITIALIZED
385 P_MMAP_FLAG(UNINITIALIZED);
386#endif
387#undef P_MMAP_FLAG
388
389 if (flags)
390 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
391
392 return printed;
393}
394
395#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
396
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300397static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300398 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300399{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300400 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300401
402 switch (behavior) {
403#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
404 P_MADV_BHV(NORMAL);
405 P_MADV_BHV(RANDOM);
406 P_MADV_BHV(SEQUENTIAL);
407 P_MADV_BHV(WILLNEED);
408 P_MADV_BHV(DONTNEED);
409 P_MADV_BHV(REMOVE);
410 P_MADV_BHV(DONTFORK);
411 P_MADV_BHV(DOFORK);
412 P_MADV_BHV(HWPOISON);
413#ifdef MADV_SOFT_OFFLINE
414 P_MADV_BHV(SOFT_OFFLINE);
415#endif
416 P_MADV_BHV(MERGEABLE);
417 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600418#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300419 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600420#endif
421#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300422 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600423#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300424#ifdef MADV_DONTDUMP
425 P_MADV_BHV(DONTDUMP);
426#endif
427#ifdef MADV_DODUMP
428 P_MADV_BHV(DODUMP);
429#endif
430#undef P_MADV_PHV
431 default: break;
432 }
433
434 return scnprintf(bf, size, "%#x", behavior);
435}
436
437#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
438
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300439static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
440 struct syscall_arg *arg)
441{
442 int printed = 0, op = arg->val;
443
444 if (op == 0)
445 return scnprintf(bf, size, "NONE");
446#define P_CMD(cmd) \
447 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
448 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
449 op &= ~LOCK_##cmd; \
450 }
451
452 P_CMD(SH);
453 P_CMD(EX);
454 P_CMD(NB);
455 P_CMD(UN);
456 P_CMD(MAND);
457 P_CMD(RW);
458 P_CMD(READ);
459 P_CMD(WRITE);
460#undef P_OP
461
462 if (op)
463 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
464
465 return printed;
466}
467
468#define SCA_FLOCK syscall_arg__scnprintf_flock
469
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300470static 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 -0300471{
472 enum syscall_futex_args {
473 SCF_UADDR = (1 << 0),
474 SCF_OP = (1 << 1),
475 SCF_VAL = (1 << 2),
476 SCF_TIMEOUT = (1 << 3),
477 SCF_UADDR2 = (1 << 4),
478 SCF_VAL3 = (1 << 5),
479 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300480 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300481 int cmd = op & FUTEX_CMD_MASK;
482 size_t printed = 0;
483
484 switch (cmd) {
485#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300486 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
487 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
488 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
489 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
490 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
491 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300492 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300493 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
494 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
495 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
496 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
497 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300498 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
499 default: printed = scnprintf(bf, size, "%#x", cmd); break;
500 }
501
502 if (op & FUTEX_PRIVATE_FLAG)
503 printed += scnprintf(bf + printed, size - printed, "|PRIV");
504
505 if (op & FUTEX_CLOCK_REALTIME)
506 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
507
508 return printed;
509}
510
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300511#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
512
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300513static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
514static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300515
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300516static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
517static DEFINE_STRARRAY(itimers);
518
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300519static const char *whences[] = { "SET", "CUR", "END",
520#ifdef SEEK_DATA
521"DATA",
522#endif
523#ifdef SEEK_HOLE
524"HOLE",
525#endif
526};
527static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300528
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300529static const char *fcntl_cmds[] = {
530 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
531 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
532 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
533 "F_GETOWNER_UIDS",
534};
535static DEFINE_STRARRAY(fcntl_cmds);
536
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300537static const char *rlimit_resources[] = {
538 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
539 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
540 "RTTIME",
541};
542static DEFINE_STRARRAY(rlimit_resources);
543
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300544static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
545static DEFINE_STRARRAY(sighow);
546
David Ahern4f8c1b72013-09-22 19:45:00 -0600547static const char *clockid[] = {
548 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
549 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
550};
551static DEFINE_STRARRAY(clockid);
552
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300553static const char *socket_families[] = {
554 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
555 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
556 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
557 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
558 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
559 "ALG", "NFC", "VSOCK",
560};
561static DEFINE_STRARRAY(socket_families);
562
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300563#ifndef SOCK_TYPE_MASK
564#define SOCK_TYPE_MASK 0xf
565#endif
566
567static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
568 struct syscall_arg *arg)
569{
570 size_t printed;
571 int type = arg->val,
572 flags = type & ~SOCK_TYPE_MASK;
573
574 type &= SOCK_TYPE_MASK;
575 /*
576 * Can't use a strarray, MIPS may override for ABI reasons.
577 */
578 switch (type) {
579#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
580 P_SK_TYPE(STREAM);
581 P_SK_TYPE(DGRAM);
582 P_SK_TYPE(RAW);
583 P_SK_TYPE(RDM);
584 P_SK_TYPE(SEQPACKET);
585 P_SK_TYPE(DCCP);
586 P_SK_TYPE(PACKET);
587#undef P_SK_TYPE
588 default:
589 printed = scnprintf(bf, size, "%#x", type);
590 }
591
592#define P_SK_FLAG(n) \
593 if (flags & SOCK_##n) { \
594 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
595 flags &= ~SOCK_##n; \
596 }
597
598 P_SK_FLAG(CLOEXEC);
599 P_SK_FLAG(NONBLOCK);
600#undef P_SK_FLAG
601
602 if (flags)
603 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
604
605 return printed;
606}
607
608#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
609
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300610#ifndef MSG_PROBE
611#define MSG_PROBE 0x10
612#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600613#ifndef MSG_WAITFORONE
614#define MSG_WAITFORONE 0x10000
615#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300616#ifndef MSG_SENDPAGE_NOTLAST
617#define MSG_SENDPAGE_NOTLAST 0x20000
618#endif
619#ifndef MSG_FASTOPEN
620#define MSG_FASTOPEN 0x20000000
621#endif
622
623static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
624 struct syscall_arg *arg)
625{
626 int printed = 0, flags = arg->val;
627
628 if (flags == 0)
629 return scnprintf(bf, size, "NONE");
630#define P_MSG_FLAG(n) \
631 if (flags & MSG_##n) { \
632 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
633 flags &= ~MSG_##n; \
634 }
635
636 P_MSG_FLAG(OOB);
637 P_MSG_FLAG(PEEK);
638 P_MSG_FLAG(DONTROUTE);
639 P_MSG_FLAG(TRYHARD);
640 P_MSG_FLAG(CTRUNC);
641 P_MSG_FLAG(PROBE);
642 P_MSG_FLAG(TRUNC);
643 P_MSG_FLAG(DONTWAIT);
644 P_MSG_FLAG(EOR);
645 P_MSG_FLAG(WAITALL);
646 P_MSG_FLAG(FIN);
647 P_MSG_FLAG(SYN);
648 P_MSG_FLAG(CONFIRM);
649 P_MSG_FLAG(RST);
650 P_MSG_FLAG(ERRQUEUE);
651 P_MSG_FLAG(NOSIGNAL);
652 P_MSG_FLAG(MORE);
653 P_MSG_FLAG(WAITFORONE);
654 P_MSG_FLAG(SENDPAGE_NOTLAST);
655 P_MSG_FLAG(FASTOPEN);
656 P_MSG_FLAG(CMSG_CLOEXEC);
657#undef P_MSG_FLAG
658
659 if (flags)
660 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
661
662 return printed;
663}
664
665#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
666
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300667static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
668 struct syscall_arg *arg)
669{
670 size_t printed = 0;
671 int mode = arg->val;
672
673 if (mode == F_OK) /* 0 */
674 return scnprintf(bf, size, "F");
675#define P_MODE(n) \
676 if (mode & n##_OK) { \
677 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
678 mode &= ~n##_OK; \
679 }
680
681 P_MODE(R);
682 P_MODE(W);
683 P_MODE(X);
684#undef P_MODE
685
686 if (mode)
687 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
688
689 return printed;
690}
691
692#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
693
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300694static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300695 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300696{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300697 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300698
699 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300700 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300701
702 if (flags == 0)
703 return scnprintf(bf, size, "RDONLY");
704#define P_FLAG(n) \
705 if (flags & O_##n) { \
706 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
707 flags &= ~O_##n; \
708 }
709
710 P_FLAG(APPEND);
711 P_FLAG(ASYNC);
712 P_FLAG(CLOEXEC);
713 P_FLAG(CREAT);
714 P_FLAG(DIRECT);
715 P_FLAG(DIRECTORY);
716 P_FLAG(EXCL);
717 P_FLAG(LARGEFILE);
718 P_FLAG(NOATIME);
719 P_FLAG(NOCTTY);
720#ifdef O_NONBLOCK
721 P_FLAG(NONBLOCK);
722#elif O_NDELAY
723 P_FLAG(NDELAY);
724#endif
725#ifdef O_PATH
726 P_FLAG(PATH);
727#endif
728 P_FLAG(RDWR);
729#ifdef O_DSYNC
730 if ((flags & O_SYNC) == O_SYNC)
731 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
732 else {
733 P_FLAG(DSYNC);
734 }
735#else
736 P_FLAG(SYNC);
737#endif
738 P_FLAG(TRUNC);
739 P_FLAG(WRONLY);
740#undef P_FLAG
741
742 if (flags)
743 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
744
745 return printed;
746}
747
748#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
749
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300750static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
751 struct syscall_arg *arg)
752{
753 int printed = 0, flags = arg->val;
754
755 if (flags == 0)
756 return scnprintf(bf, size, "NONE");
757#define P_FLAG(n) \
758 if (flags & EFD_##n) { \
759 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
760 flags &= ~EFD_##n; \
761 }
762
763 P_FLAG(SEMAPHORE);
764 P_FLAG(CLOEXEC);
765 P_FLAG(NONBLOCK);
766#undef P_FLAG
767
768 if (flags)
769 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
770
771 return printed;
772}
773
774#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
775
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300776static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
777 struct syscall_arg *arg)
778{
779 int printed = 0, flags = arg->val;
780
781#define P_FLAG(n) \
782 if (flags & O_##n) { \
783 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
784 flags &= ~O_##n; \
785 }
786
787 P_FLAG(CLOEXEC);
788 P_FLAG(NONBLOCK);
789#undef P_FLAG
790
791 if (flags)
792 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
793
794 return printed;
795}
796
797#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
798
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300799static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
800{
801 int sig = arg->val;
802
803 switch (sig) {
804#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
805 P_SIGNUM(HUP);
806 P_SIGNUM(INT);
807 P_SIGNUM(QUIT);
808 P_SIGNUM(ILL);
809 P_SIGNUM(TRAP);
810 P_SIGNUM(ABRT);
811 P_SIGNUM(BUS);
812 P_SIGNUM(FPE);
813 P_SIGNUM(KILL);
814 P_SIGNUM(USR1);
815 P_SIGNUM(SEGV);
816 P_SIGNUM(USR2);
817 P_SIGNUM(PIPE);
818 P_SIGNUM(ALRM);
819 P_SIGNUM(TERM);
820 P_SIGNUM(STKFLT);
821 P_SIGNUM(CHLD);
822 P_SIGNUM(CONT);
823 P_SIGNUM(STOP);
824 P_SIGNUM(TSTP);
825 P_SIGNUM(TTIN);
826 P_SIGNUM(TTOU);
827 P_SIGNUM(URG);
828 P_SIGNUM(XCPU);
829 P_SIGNUM(XFSZ);
830 P_SIGNUM(VTALRM);
831 P_SIGNUM(PROF);
832 P_SIGNUM(WINCH);
833 P_SIGNUM(IO);
834 P_SIGNUM(PWR);
835 P_SIGNUM(SYS);
836 default: break;
837 }
838
839 return scnprintf(bf, size, "%#x", sig);
840}
841
842#define SCA_SIGNUM syscall_arg__scnprintf_signum
843
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300844#define TCGETS 0x5401
845
846static const char *tioctls[] = {
847 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
848 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
849 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
850 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
851 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
852 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
853 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
854 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
855 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
856 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
857 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
858 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
859 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
860 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
861 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
862};
863
864static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
865
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300866#define STRARRAY(arg, name, array) \
867 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
868 .arg_parm = { [arg] = &strarray__##array, }
869
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300870static struct syscall_fmt {
871 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300872 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300873 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300874 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300875 bool errmsg;
876 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300877 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300878} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300879 { .name = "access", .errmsg = true,
880 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300881 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300882 { .name = "brk", .hexret = true,
883 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600884 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300885 { .name = "close", .errmsg = true,
886 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300887 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300888 { .name = "dup", .errmsg = true,
889 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
890 { .name = "dup2", .errmsg = true,
891 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
892 { .name = "dup3", .errmsg = true,
893 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300894 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300895 { .name = "eventfd2", .errmsg = true,
896 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300897 { .name = "faccessat", .errmsg = true,
898 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
899 { .name = "fadvise64", .errmsg = true,
900 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
901 { .name = "fallocate", .errmsg = true,
902 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
903 { .name = "fchdir", .errmsg = true,
904 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
905 { .name = "fchmod", .errmsg = true,
906 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
907 { .name = "fchmodat", .errmsg = true,
908 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
909 { .name = "fchown", .errmsg = true,
910 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
911 { .name = "fchownat", .errmsg = true,
912 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
913 { .name = "fcntl", .errmsg = true,
914 .arg_scnprintf = { [0] = SCA_FD, /* fd */
915 [1] = SCA_STRARRAY, /* cmd */ },
916 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
917 { .name = "fdatasync", .errmsg = true,
918 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300919 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300920 .arg_scnprintf = { [0] = SCA_FD, /* fd */
921 [1] = SCA_FLOCK, /* cmd */ }, },
922 { .name = "fsetxattr", .errmsg = true,
923 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
924 { .name = "fstat", .errmsg = true, .alias = "newfstat",
925 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
926 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
927 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
928 { .name = "fstatfs", .errmsg = true,
929 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
930 { .name = "fsync", .errmsg = true,
931 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
932 { .name = "ftruncate", .errmsg = true,
933 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300934 { .name = "futex", .errmsg = true,
935 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300936 { .name = "futimesat", .errmsg = true,
937 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
938 { .name = "getdents", .errmsg = true,
939 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
940 { .name = "getdents64", .errmsg = true,
941 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300942 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
943 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300944 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300945 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300946 [1] = SCA_STRHEXARRAY, /* cmd */
947 [2] = SCA_HEX, /* arg */ },
948 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300949 { .name = "kill", .errmsg = true,
950 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300951 { .name = "linkat", .errmsg = true,
952 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
953 { .name = "lseek", .errmsg = true,
954 .arg_scnprintf = { [0] = SCA_FD, /* fd */
955 [2] = SCA_STRARRAY, /* whence */ },
956 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300957 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300958 { .name = "madvise", .errmsg = true,
959 .arg_scnprintf = { [0] = SCA_HEX, /* start */
960 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300961 { .name = "mkdirat", .errmsg = true,
962 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
963 { .name = "mknodat", .errmsg = true,
964 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300965 { .name = "mlock", .errmsg = true,
966 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
967 { .name = "mlockall", .errmsg = true,
968 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300969 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300970 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300971 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +0900972 [3] = SCA_MMAP_FLAGS, /* flags */
973 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300974 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300975 .arg_scnprintf = { [0] = SCA_HEX, /* start */
976 [2] = SCA_MMAP_PROT, /* prot */ }, },
977 { .name = "mremap", .hexret = true,
978 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
979 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300980 { .name = "munlock", .errmsg = true,
981 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300982 { .name = "munmap", .errmsg = true,
983 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300984 { .name = "name_to_handle_at", .errmsg = true,
985 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
986 { .name = "newfstatat", .errmsg = true,
987 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300988 { .name = "open", .errmsg = true,
989 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300990 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300991 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
992 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300993 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300994 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
995 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300996 { .name = "pipe2", .errmsg = true,
997 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300998 { .name = "poll", .errmsg = true, .timeout = true, },
999 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001000 { .name = "pread", .errmsg = true, .alias = "pread64",
1001 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1002 { .name = "preadv", .errmsg = true, .alias = "pread",
1003 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001004 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001005 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
1006 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1007 { .name = "pwritev", .errmsg = true,
1008 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1009 { .name = "read", .errmsg = true,
1010 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1011 { .name = "readlinkat", .errmsg = true,
1012 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1013 { .name = "readv", .errmsg = true,
1014 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001015 { .name = "recvfrom", .errmsg = true,
1016 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1017 { .name = "recvmmsg", .errmsg = true,
1018 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1019 { .name = "recvmsg", .errmsg = true,
1020 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001021 { .name = "renameat", .errmsg = true,
1022 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001023 { .name = "rt_sigaction", .errmsg = true,
1024 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001025 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001026 { .name = "rt_sigqueueinfo", .errmsg = true,
1027 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1028 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1029 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001030 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001031 { .name = "sendmmsg", .errmsg = true,
1032 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1033 { .name = "sendmsg", .errmsg = true,
1034 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
1035 { .name = "sendto", .errmsg = true,
1036 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001037 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1038 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001039 { .name = "shutdown", .errmsg = true,
1040 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001041 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001042 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1043 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001044 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001045 { .name = "socketpair", .errmsg = true,
1046 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1047 [1] = SCA_SK_TYPE, /* type */ },
1048 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001049 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001050 { .name = "symlinkat", .errmsg = true,
1051 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001052 { .name = "tgkill", .errmsg = true,
1053 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1054 { .name = "tkill", .errmsg = true,
1055 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001056 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001057 { .name = "unlinkat", .errmsg = true,
1058 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1059 { .name = "utimensat", .errmsg = true,
1060 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
1061 { .name = "write", .errmsg = true,
1062 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1063 { .name = "writev", .errmsg = true,
1064 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001065};
1066
1067static int syscall_fmt__cmp(const void *name, const void *fmtp)
1068{
1069 const struct syscall_fmt *fmt = fmtp;
1070 return strcmp(name, fmt->name);
1071}
1072
1073static struct syscall_fmt *syscall_fmt__find(const char *name)
1074{
1075 const int nmemb = ARRAY_SIZE(syscall_fmts);
1076 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1077}
1078
1079struct syscall {
1080 struct event_format *tp_format;
1081 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001082 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001083 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001084 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001085 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001086};
1087
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001088static size_t fprintf_duration(unsigned long t, FILE *fp)
1089{
1090 double duration = (double)t / NSEC_PER_MSEC;
1091 size_t printed = fprintf(fp, "(");
1092
1093 if (duration >= 1.0)
1094 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1095 else if (duration >= 0.01)
1096 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1097 else
1098 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001099 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001100}
1101
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001102struct thread_trace {
1103 u64 entry_time;
1104 u64 exit_time;
1105 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001106 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001107 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001108 double runtime_ms;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001109 struct {
1110 int max;
1111 char **table;
1112 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001113
1114 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001115};
1116
1117static struct thread_trace *thread_trace__new(void)
1118{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001119 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1120
1121 if (ttrace)
1122 ttrace->paths.max = -1;
1123
David Ahernbf2575c2013-10-08 21:26:53 -06001124 ttrace->syscall_stats = intlist__new(NULL);
1125
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001126 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001127}
1128
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001129static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001130{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001131 struct thread_trace *ttrace;
1132
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001133 if (thread == NULL)
1134 goto fail;
1135
1136 if (thread->priv == NULL)
1137 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001138
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001139 if (thread->priv == NULL)
1140 goto fail;
1141
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001142 ttrace = thread->priv;
1143 ++ttrace->nr_events;
1144
1145 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001146fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001147 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001148 "WARNING: not enough memory, dropping samples!\n");
1149 return NULL;
1150}
1151
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001152struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001153 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001154 struct {
1155 int machine;
1156 int open_id;
1157 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001158 struct {
1159 int max;
1160 struct syscall *table;
1161 } syscalls;
1162 struct perf_record_opts opts;
David Ahern8fb598e2013-09-28 13:13:00 -06001163 struct machine *host;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001164 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -06001165 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001166 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001167 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001168 struct strlist *ev_qualifier;
1169 bool not_ev_qualifier;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001170 bool live;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001171 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -06001172 struct intlist *tid_list;
1173 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001174 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001175 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001176 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001177 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001178 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001179 bool show_tool_stats;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001180 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001181 double runtime_ms;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001182 struct {
1183 u64 vfs_getname, proc_getname;
1184 } stats;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001185};
1186
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001187static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001188{
1189 struct thread_trace *ttrace = thread->priv;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001190
1191 if (fd > ttrace->paths.max) {
1192 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1193
1194 if (npath == NULL)
1195 return -1;
1196
1197 if (ttrace->paths.max != -1) {
1198 memset(npath + ttrace->paths.max + 1, 0,
1199 (fd - ttrace->paths.max) * sizeof(char *));
1200 } else {
1201 memset(npath, 0, (fd + 1) * sizeof(char *));
1202 }
1203
1204 ttrace->paths.table = npath;
1205 ttrace->paths.max = fd;
1206 }
1207
1208 ttrace->paths.table[fd] = strdup(pathname);
1209
1210 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1211}
1212
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001213static int thread__read_fd_path(struct thread *thread, int fd)
1214{
1215 char linkname[PATH_MAX], pathname[PATH_MAX];
1216 struct stat st;
1217 int ret;
1218
1219 if (thread->pid_ == thread->tid) {
1220 scnprintf(linkname, sizeof(linkname),
1221 "/proc/%d/fd/%d", thread->pid_, fd);
1222 } else {
1223 scnprintf(linkname, sizeof(linkname),
1224 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1225 }
1226
1227 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1228 return -1;
1229
1230 ret = readlink(linkname, pathname, sizeof(pathname));
1231
1232 if (ret < 0 || ret > st.st_size)
1233 return -1;
1234
1235 pathname[ret] = '\0';
1236 return trace__set_fd_pathname(thread, fd, pathname);
1237}
1238
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001239static const char *thread__fd_path(struct thread *thread, int fd,
1240 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001241{
1242 struct thread_trace *ttrace = thread->priv;
1243
1244 if (ttrace == NULL)
1245 return NULL;
1246
1247 if (fd < 0)
1248 return NULL;
1249
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001250 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL))
1251 if (!trace->live)
1252 return NULL;
1253 ++trace->stats.proc_getname;
1254 if (thread__read_fd_path(thread, fd)) {
1255 return NULL;
1256 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001257
1258 return ttrace->paths.table[fd];
1259}
1260
1261static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1262 struct syscall_arg *arg)
1263{
1264 int fd = arg->val;
1265 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001266 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001267
1268 if (path)
1269 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1270
1271 return printed;
1272}
1273
1274static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1275 struct syscall_arg *arg)
1276{
1277 int fd = arg->val;
1278 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1279 struct thread_trace *ttrace = arg->thread->priv;
1280
1281 if (ttrace && fd >= 0 && fd <= ttrace->paths.max) {
1282 free(ttrace->paths.table[fd]);
1283 ttrace->paths.table[fd] = NULL;
1284 }
1285
1286 return printed;
1287}
1288
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001289static bool trace__filter_duration(struct trace *trace, double t)
1290{
1291 return t < (trace->duration_filter * NSEC_PER_MSEC);
1292}
1293
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001294static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1295{
1296 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1297
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001298 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001299}
1300
Namhyung Kimf15eb532012-10-05 14:02:16 +09001301static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001302static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001303
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001304static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001305{
1306 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001307 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001308}
1309
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001310static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001311 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001312{
1313 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001314 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001315
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001316 if (trace->multiple_threads) {
1317 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001318 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001319 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001320 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001321
1322 return printed;
1323}
1324
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001325static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001326 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001327{
1328 int ret = 0;
1329
1330 switch (event->header.type) {
1331 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001332 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001333 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001334 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001335 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001336 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001337 break;
1338 }
1339
1340 return ret;
1341}
1342
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001343static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001344 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001345 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001346 struct machine *machine)
1347{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001348 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001349 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001350}
1351
1352static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1353{
1354 int err = symbol__init();
1355
1356 if (err)
1357 return err;
1358
David Ahern8fb598e2013-09-28 13:13:00 -06001359 trace->host = machine__new_host();
1360 if (trace->host == NULL)
1361 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001362
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001363 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
1364 evlist->threads, trace__tool_process, false);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001365 if (err)
1366 symbol__exit();
1367
1368 return err;
1369}
1370
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001371static int syscall__set_arg_fmts(struct syscall *sc)
1372{
1373 struct format_field *field;
1374 int idx = 0;
1375
1376 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1377 if (sc->arg_scnprintf == NULL)
1378 return -1;
1379
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001380 if (sc->fmt)
1381 sc->arg_parm = sc->fmt->arg_parm;
1382
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001383 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001384 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1385 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1386 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001387 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1388 ++idx;
1389 }
1390
1391 return 0;
1392}
1393
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001394static int trace__read_syscall_info(struct trace *trace, int id)
1395{
1396 char tp_name[128];
1397 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001398 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001399
1400 if (name == NULL)
1401 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001402
1403 if (id > trace->syscalls.max) {
1404 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1405
1406 if (nsyscalls == NULL)
1407 return -1;
1408
1409 if (trace->syscalls.max != -1) {
1410 memset(nsyscalls + trace->syscalls.max + 1, 0,
1411 (id - trace->syscalls.max) * sizeof(*sc));
1412 } else {
1413 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1414 }
1415
1416 trace->syscalls.table = nsyscalls;
1417 trace->syscalls.max = id;
1418 }
1419
1420 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001421 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001422
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001423 if (trace->ev_qualifier) {
1424 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1425
1426 if (!(in ^ trace->not_ev_qualifier)) {
1427 sc->filtered = true;
1428 /*
1429 * No need to do read tracepoint information since this will be
1430 * filtered out.
1431 */
1432 return 0;
1433 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001434 }
1435
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001436 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001437
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001438 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001439 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001440
1441 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1442 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001443 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001444 }
1445
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001446 if (sc->tp_format == NULL)
1447 return -1;
1448
1449 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001450}
1451
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001452static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001453 unsigned long *args, struct trace *trace,
1454 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001455{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001456 size_t printed = 0;
1457
1458 if (sc->tp_format != NULL) {
1459 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001460 u8 bit = 1;
1461 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001462 .idx = 0,
1463 .mask = 0,
1464 .trace = trace,
1465 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001466 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001467
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001468 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001469 field = field->next, ++arg.idx, bit <<= 1) {
1470 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001471 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001472 /*
1473 * Suppress this argument if its value is zero and
1474 * and we don't have a string associated in an
1475 * strarray for it.
1476 */
1477 if (args[arg.idx] == 0 &&
1478 !(sc->arg_scnprintf &&
1479 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1480 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001481 continue;
1482
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001483 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001484 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001485 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1486 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001487 if (sc->arg_parm)
1488 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001489 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1490 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001491 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001492 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001493 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001494 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001495 }
1496 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001497 int i = 0;
1498
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001499 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001500 printed += scnprintf(bf + printed, size - printed,
1501 "%sarg%d: %ld",
1502 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001503 ++i;
1504 }
1505 }
1506
1507 return printed;
1508}
1509
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001510typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1511 struct perf_sample *sample);
1512
1513static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001514 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001515{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001516
1517 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001518
1519 /*
1520 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1521 * before that, leaving at a higher verbosity level till that is
1522 * explained. Reproduced with plain ftrace with:
1523 *
1524 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1525 * grep "NR -1 " /t/trace_pipe
1526 *
1527 * After generating some load on the machine.
1528 */
1529 if (verbose > 1) {
1530 static u64 n;
1531 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1532 id, perf_evsel__name(evsel), ++n);
1533 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001534 return NULL;
1535 }
1536
1537 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1538 trace__read_syscall_info(trace, id))
1539 goto out_cant_read;
1540
1541 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1542 goto out_cant_read;
1543
1544 return &trace->syscalls.table[id];
1545
1546out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001547 if (verbose) {
1548 fprintf(trace->output, "Problems reading syscall %d", id);
1549 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1550 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1551 fputs(" information\n", trace->output);
1552 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001553 return NULL;
1554}
1555
David Ahernbf2575c2013-10-08 21:26:53 -06001556static void thread__update_stats(struct thread_trace *ttrace,
1557 int id, struct perf_sample *sample)
1558{
1559 struct int_node *inode;
1560 struct stats *stats;
1561 u64 duration = 0;
1562
1563 inode = intlist__findnew(ttrace->syscall_stats, id);
1564 if (inode == NULL)
1565 return;
1566
1567 stats = inode->priv;
1568 if (stats == NULL) {
1569 stats = malloc(sizeof(struct stats));
1570 if (stats == NULL)
1571 return;
1572 init_stats(stats);
1573 inode->priv = stats;
1574 }
1575
1576 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1577 duration = sample->time - ttrace->entry_time;
1578
1579 update_stats(stats, duration);
1580}
1581
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001582static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1583 struct perf_sample *sample)
1584{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001585 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001586 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001587 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001588 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001589 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001590 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001591 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001592
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001593 if (sc == NULL)
1594 return -1;
1595
1596 if (sc->filtered)
1597 return 0;
1598
David Ahern8fb598e2013-09-28 13:13:00 -06001599 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001600 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001601 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001602 return -1;
1603
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001604 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001605 ttrace = thread->priv;
1606
1607 if (ttrace->entry_str == NULL) {
1608 ttrace->entry_str = malloc(1024);
1609 if (!ttrace->entry_str)
1610 return -1;
1611 }
1612
1613 ttrace->entry_time = sample->time;
1614 msg = ttrace->entry_str;
1615 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1616
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001617 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1618 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001619
1620 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001621 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001622 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1623 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001624 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001625 } else
1626 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001627
1628 return 0;
1629}
1630
1631static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1632 struct perf_sample *sample)
1633{
1634 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001635 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001636 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001637 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001638 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001639 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001640
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001641 if (sc == NULL)
1642 return -1;
1643
1644 if (sc->filtered)
1645 return 0;
1646
David Ahern8fb598e2013-09-28 13:13:00 -06001647 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001648 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001649 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001650 return -1;
1651
David Ahernbf2575c2013-10-08 21:26:53 -06001652 if (trace->summary)
1653 thread__update_stats(ttrace, id, sample);
1654
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001655 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001656
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001657 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1658 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1659 trace->last_vfs_getname = NULL;
1660 ++trace->stats.vfs_getname;
1661 }
1662
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001663 ttrace = thread->priv;
1664
1665 ttrace->exit_time = sample->time;
1666
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001667 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001668 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001669 if (trace__filter_duration(trace, duration))
1670 goto out;
1671 } else if (trace->duration_filter)
1672 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001673
David Ahernfd2eaba2013-11-12 09:31:15 -07001674 if (trace->summary_only)
1675 goto out;
1676
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001677 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001678
1679 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001680 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001681 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001682 fprintf(trace->output, " ... [");
1683 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1684 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001685 }
1686
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001687 if (sc->fmt == NULL) {
1688signed_print:
1689 fprintf(trace->output, ") = %d", ret);
1690 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001691 char bf[256];
1692 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1693 *e = audit_errno_to_name(-ret);
1694
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001695 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001696 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001697 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001698 else if (sc->fmt->hexret)
1699 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001700 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001701 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001702
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001703 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001704out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001705 ttrace->entry_pending = false;
1706
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001707 return 0;
1708}
1709
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001710static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1711 struct perf_sample *sample)
1712{
1713 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1714 return 0;
1715}
1716
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001717static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1718 struct perf_sample *sample)
1719{
1720 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1721 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001722 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001723 sample->pid,
1724 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001725 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001726
1727 if (ttrace == NULL)
1728 goto out_dump;
1729
1730 ttrace->runtime_ms += runtime_ms;
1731 trace->runtime_ms += runtime_ms;
1732 return 0;
1733
1734out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001735 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001736 evsel->name,
1737 perf_evsel__strval(evsel, sample, "comm"),
1738 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1739 runtime,
1740 perf_evsel__intval(evsel, sample, "vruntime"));
1741 return 0;
1742}
1743
David Ahernbdc89662013-08-28 22:29:53 -06001744static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1745{
1746 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1747 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1748 return false;
1749
1750 if (trace->pid_list || trace->tid_list)
1751 return true;
1752
1753 return false;
1754}
1755
David Ahern6810fc92013-08-28 22:29:52 -06001756static int trace__process_sample(struct perf_tool *tool,
1757 union perf_event *event __maybe_unused,
1758 struct perf_sample *sample,
1759 struct perf_evsel *evsel,
1760 struct machine *machine __maybe_unused)
1761{
1762 struct trace *trace = container_of(tool, struct trace, tool);
1763 int err = 0;
1764
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001765 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001766
David Ahernbdc89662013-08-28 22:29:53 -06001767 if (skip_sample(trace, sample))
1768 return 0;
1769
David Ahern4bb09192013-09-04 12:37:43 -06001770 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001771 trace->base_time = sample->time;
1772
1773 if (handler)
1774 handler(trace, evsel, sample);
1775
1776 return err;
1777}
1778
David Ahernbdc89662013-08-28 22:29:53 -06001779static int parse_target_str(struct trace *trace)
1780{
1781 if (trace->opts.target.pid) {
1782 trace->pid_list = intlist__new(trace->opts.target.pid);
1783 if (trace->pid_list == NULL) {
1784 pr_err("Error parsing process id string\n");
1785 return -EINVAL;
1786 }
1787 }
1788
1789 if (trace->opts.target.tid) {
1790 trace->tid_list = intlist__new(trace->opts.target.tid);
1791 if (trace->tid_list == NULL) {
1792 pr_err("Error parsing thread id string\n");
1793 return -EINVAL;
1794 }
1795 }
1796
1797 return 0;
1798}
1799
David Ahern5e2485b2013-09-28 13:13:01 -06001800static int trace__record(int argc, const char **argv)
1801{
1802 unsigned int rec_argc, i, j;
1803 const char **rec_argv;
1804 const char * const record_args[] = {
1805 "record",
1806 "-R",
1807 "-m", "1024",
1808 "-c", "1",
David Ahern9aca7f12013-12-04 19:41:39 -07001809 "-e",
David Ahern5e2485b2013-09-28 13:13:01 -06001810 };
1811
David Ahern9aca7f12013-12-04 19:41:39 -07001812 /* +1 is for the event string below */
1813 rec_argc = ARRAY_SIZE(record_args) + 1 + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06001814 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1815
1816 if (rec_argv == NULL)
1817 return -ENOMEM;
1818
1819 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1820 rec_argv[i] = record_args[i];
1821
David Ahern9aca7f12013-12-04 19:41:39 -07001822 /* event string may be different for older kernels - e.g., RHEL6 */
1823 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
1824 rec_argv[i] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
1825 else if (is_valid_tracepoint("syscalls:sys_enter"))
1826 rec_argv[i] = "syscalls:sys_enter,syscalls:sys_exit";
1827 else {
1828 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
1829 return -1;
1830 }
1831 i++;
1832
David Ahern5e2485b2013-09-28 13:13:01 -06001833 for (j = 0; j < (unsigned int)argc; j++, i++)
1834 rec_argv[i] = argv[j];
1835
1836 return cmd_record(i, rec_argv, NULL);
1837}
1838
David Ahernbf2575c2013-10-08 21:26:53 -06001839static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
1840
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001841static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
1842{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03001843 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001844 if (evsel == NULL)
1845 return;
1846
1847 if (perf_evsel__field(evsel, "pathname") == NULL) {
1848 perf_evsel__delete(evsel);
1849 return;
1850 }
1851
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001852 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001853 perf_evlist__add(evlist, evsel);
1854}
1855
Namhyung Kimf15eb532012-10-05 14:02:16 +09001856static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001857{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001858 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001859 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001860 int err = -1, i;
1861 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001862 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001863
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001864 trace->live = true;
1865
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001866 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001867 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001868 goto out;
1869 }
1870
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001871 if (perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, trace__sys_exit))
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301872 goto out_error_tp;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001873
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001874 perf_evlist__add_vfs_getname(evlist);
1875
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001876 if (trace->sched &&
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301877 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1878 trace__sched_stat_runtime))
1879 goto out_error_tp;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001880
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001881 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1882 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001883 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001884 goto out_delete_evlist;
1885 }
1886
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001887 err = trace__symbols_init(trace, evlist);
1888 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001889 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001890 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001891 }
1892
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001893 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001894
Namhyung Kimf15eb532012-10-05 14:02:16 +09001895 signal(SIGCHLD, sig_handler);
1896 signal(SIGINT, sig_handler);
1897
1898 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001899 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001900 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001901 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001902 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001903 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001904 }
1905 }
1906
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001907 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03001908 if (err < 0)
1909 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001910
Jiri Olsaf8850372013-11-28 17:57:22 +01001911 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001912 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001913 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001914 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001915 }
1916
1917 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001918
1919 if (forks)
1920 perf_evlist__start_workload(evlist);
1921
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001922 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001923again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001924 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001925
1926 for (i = 0; i < evlist->nr_mmaps; i++) {
1927 union perf_event *event;
1928
1929 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1930 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001931 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001932 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001933
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001934 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001935
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001936 err = perf_evlist__parse_sample(evlist, event, &sample);
1937 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001938 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001939 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001940 }
1941
David Ahern4bb09192013-09-04 12:37:43 -06001942 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001943 trace->base_time = sample.time;
1944
1945 if (type != PERF_RECORD_SAMPLE) {
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001946 trace__process_event(trace, trace->host, event, &sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001947 continue;
1948 }
1949
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001950 evsel = perf_evlist__id2evsel(evlist, sample.id);
1951 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001952 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001953 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001954 }
1955
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001956 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001957 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 -03001958 perf_evsel__name(evsel), sample.tid,
1959 sample.cpu, sample.raw_size);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001960 goto next_event;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001961 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001962
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001963 handler = evsel->handler;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001964 handler(trace, evsel, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001965next_event:
1966 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001967
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001968 if (interrupted)
1969 goto out_disable;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001970 }
1971 }
1972
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001973 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001974 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001975
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001976 if (poll(evlist->pollfd, evlist->nr_fds, timeout) > 0)
1977 goto again;
1978 } else {
1979 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001980 }
1981
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001982out_disable:
1983 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001984
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001985 if (!err) {
1986 if (trace->summary)
1987 trace__fprintf_thread_summary(trace, trace->output);
1988
1989 if (trace->show_tool_stats) {
1990 fprintf(trace->output, "Stats:\n "
1991 " vfs_getname : %" PRIu64 "\n"
1992 " proc_getname: %" PRIu64 "\n",
1993 trace->stats.vfs_getname,
1994 trace->stats.proc_getname);
1995 }
1996 }
David Ahernbf2575c2013-10-08 21:26:53 -06001997
Namhyung Kim3beb0862013-03-15 14:48:50 +09001998 perf_evlist__munmap(evlist);
1999out_close_evlist:
2000 perf_evlist__close(evlist);
2001out_delete_maps:
2002 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002003out_delete_evlist:
2004 perf_evlist__delete(evlist);
2005out:
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002006 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002007 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002008{
2009 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002010
2011out_error_tp:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002012 perf_evlist__strerror_tp(evlist, errno, errbuf, sizeof(errbuf));
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002013 goto out_error;
2014
2015out_error_open:
2016 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2017
2018out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002019 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302020 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002021}
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002022}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002023
David Ahern6810fc92013-08-28 22:29:52 -06002024static int trace__replay(struct trace *trace)
2025{
2026 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002027 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002028 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002029 struct perf_data_file file = {
2030 .path = input_name,
2031 .mode = PERF_DATA_MODE_READ,
2032 };
David Ahern6810fc92013-08-28 22:29:52 -06002033 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002034 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002035 int err = -1;
2036
2037 trace->tool.sample = trace__process_sample;
2038 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002039 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002040 trace->tool.comm = perf_event__process_comm;
2041 trace->tool.exit = perf_event__process_exit;
2042 trace->tool.fork = perf_event__process_fork;
2043 trace->tool.attr = perf_event__process_attr;
2044 trace->tool.tracing_data = perf_event__process_tracing_data;
2045 trace->tool.build_id = perf_event__process_build_id;
2046
2047 trace->tool.ordered_samples = true;
2048 trace->tool.ordering_requires_timestamps = true;
2049
2050 /* add tid to output */
2051 trace->multiple_threads = true;
2052
2053 if (symbol__init() < 0)
2054 return -1;
2055
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002056 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002057 if (session == NULL)
2058 return -ENOMEM;
2059
David Ahern8fb598e2013-09-28 13:13:00 -06002060 trace->host = &session->machines.host;
2061
David Ahern6810fc92013-08-28 22:29:52 -06002062 err = perf_session__set_tracepoints_handlers(session, handlers);
2063 if (err)
2064 goto out;
2065
Namhyung Kim003824e2013-11-12 15:25:00 +09002066 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2067 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002068 /* older kernels have syscalls tp versus raw_syscalls */
2069 if (evsel == NULL)
2070 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2071 "syscalls:sys_enter");
Namhyung Kim003824e2013-11-12 15:25:00 +09002072 if (evsel == NULL) {
2073 pr_err("Data file does not have raw_syscalls:sys_enter event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002074 goto out;
2075 }
2076
Namhyung Kim003824e2013-11-12 15:25:00 +09002077 if (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2078 perf_evsel__init_sc_tp_ptr_field(evsel, args)) {
2079 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2080 goto out;
2081 }
2082
2083 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2084 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002085 if (evsel == NULL)
2086 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2087 "syscalls:sys_exit");
Namhyung Kim003824e2013-11-12 15:25:00 +09002088 if (evsel == NULL) {
2089 pr_err("Data file does not have raw_syscalls:sys_exit event\n");
2090 goto out;
2091 }
2092
2093 if (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2094 perf_evsel__init_sc_tp_uint_field(evsel, ret)) {
2095 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002096 goto out;
2097 }
2098
David Ahernbdc89662013-08-28 22:29:53 -06002099 err = parse_target_str(trace);
2100 if (err != 0)
2101 goto out;
2102
David Ahern6810fc92013-08-28 22:29:52 -06002103 setup_pager();
2104
2105 err = perf_session__process_events(session, &trace->tool);
2106 if (err)
2107 pr_err("Failed to process events, error %d", err);
2108
David Ahernbf2575c2013-10-08 21:26:53 -06002109 else if (trace->summary)
2110 trace__fprintf_thread_summary(trace, trace->output);
2111
David Ahern6810fc92013-08-28 22:29:52 -06002112out:
2113 perf_session__delete(session);
2114
2115 return err;
2116}
2117
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002118static size_t trace__fprintf_threads_header(FILE *fp)
2119{
2120 size_t printed;
2121
Pekka Enberg99ff7152013-11-12 16:42:14 +02002122 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002123
2124 return printed;
2125}
2126
2127static size_t thread__dump_stats(struct thread_trace *ttrace,
2128 struct trace *trace, FILE *fp)
2129{
2130 struct stats *stats;
2131 size_t printed = 0;
2132 struct syscall *sc;
2133 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2134
2135 if (inode == NULL)
2136 return 0;
2137
2138 printed += fprintf(fp, "\n");
2139
Pekka Enberg27a778b2013-11-13 14:21:48 +02002140 printed += fprintf(fp, " syscall calls min avg max stddev\n");
2141 printed += fprintf(fp, " (msec) (msec) (msec) (%%)\n");
2142 printed += fprintf(fp, " --------------- -------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002143
David Ahernbf2575c2013-10-08 21:26:53 -06002144 /* each int_node is a syscall */
2145 while (inode) {
2146 stats = inode->priv;
2147 if (stats) {
2148 double min = (double)(stats->min) / NSEC_PER_MSEC;
2149 double max = (double)(stats->max) / NSEC_PER_MSEC;
2150 double avg = avg_stats(stats);
2151 double pct;
2152 u64 n = (u64) stats->n;
2153
2154 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2155 avg /= NSEC_PER_MSEC;
2156
2157 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002158 printed += fprintf(fp, " %-15s", sc->name);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002159 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f",
Pekka Enberg7f7a4132013-11-12 16:10:10 +02002160 n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002161 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002162 }
2163
2164 inode = intlist__next(inode);
2165 }
2166
2167 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002168
2169 return printed;
2170}
2171
David Ahern896cbb52013-09-28 13:12:59 -06002172/* struct used to pass data to per-thread function */
2173struct summary_data {
2174 FILE *fp;
2175 struct trace *trace;
2176 size_t printed;
2177};
2178
2179static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2180{
2181 struct summary_data *data = priv;
2182 FILE *fp = data->fp;
2183 size_t printed = data->printed;
2184 struct trace *trace = data->trace;
2185 struct thread_trace *ttrace = thread->priv;
David Ahern896cbb52013-09-28 13:12:59 -06002186 double ratio;
2187
2188 if (ttrace == NULL)
2189 return 0;
2190
2191 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2192
Pekka Enberg15e65c62013-11-14 18:43:30 +02002193 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002194 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002195 printed += fprintf(fp, "%.1f%%", ratio);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002196 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002197 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002198
2199 data->printed += printed;
2200
2201 return 0;
2202}
2203
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002204static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2205{
David Ahern896cbb52013-09-28 13:12:59 -06002206 struct summary_data data = {
2207 .fp = fp,
2208 .trace = trace
2209 };
2210 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002211
David Ahern896cbb52013-09-28 13:12:59 -06002212 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002213
David Ahern896cbb52013-09-28 13:12:59 -06002214 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002215}
2216
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002217static int trace__set_duration(const struct option *opt, const char *str,
2218 int unset __maybe_unused)
2219{
2220 struct trace *trace = opt->value;
2221
2222 trace->duration_filter = atof(str);
2223 return 0;
2224}
2225
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002226static int trace__open_output(struct trace *trace, const char *filename)
2227{
2228 struct stat st;
2229
2230 if (!stat(filename, &st) && st.st_size) {
2231 char oldname[PATH_MAX];
2232
2233 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2234 unlink(oldname);
2235 rename(filename, oldname);
2236 }
2237
2238 trace->output = fopen(filename, "w");
2239
2240 return trace->output == NULL ? -errno : 0;
2241}
2242
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002243int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2244{
2245 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002246 "perf trace [<options>] [<command>]",
2247 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002248 "perf trace record [<options>] [<command>]",
2249 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002250 NULL
2251 };
2252 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002253 .audit = {
2254 .machine = audit_detect_machine(),
2255 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2256 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002257 .syscalls = {
2258 . max = -1,
2259 },
2260 .opts = {
2261 .target = {
2262 .uid = UINT_MAX,
2263 .uses_mmap = true,
2264 },
2265 .user_freq = UINT_MAX,
2266 .user_interval = ULLONG_MAX,
2267 .no_delay = true,
2268 .mmap_pages = 1024,
2269 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002270 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002271 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002272 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002273 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002274 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002275 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002276 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2277 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002278 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002279 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
2280 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002281 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002282 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002283 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2284 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002285 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002286 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002287 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002288 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002289 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002290 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002291 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002292 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002293 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2294 "number of mmap data pages",
2295 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002296 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002297 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002298 OPT_CALLBACK(0, "duration", &trace, "float",
2299 "show only events with duration > N.M ms",
2300 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002301 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002302 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002303 OPT_BOOLEAN('T', "time", &trace.full_time,
2304 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002305 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2306 "Show only syscall summary with statistics"),
2307 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2308 "Show all syscalls and summary with statistics"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002309 OPT_END()
2310 };
2311 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002312 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002313
David Ahern5e2485b2013-09-28 13:13:01 -06002314 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
2315 return trace__record(argc-2, &argv[2]);
2316
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002317 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002318
David Ahernfd2eaba2013-11-12 09:31:15 -07002319 /* summary_only implies summary option, but don't overwrite summary if set */
2320 if (trace.summary_only)
2321 trace.summary = trace.summary_only;
2322
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002323 if (output_name != NULL) {
2324 err = trace__open_output(&trace, output_name);
2325 if (err < 0) {
2326 perror("failed to create output file");
2327 goto out;
2328 }
2329 }
2330
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002331 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002332 const char *s = ev_qualifier_str;
2333
2334 trace.not_ev_qualifier = *s == '!';
2335 if (trace.not_ev_qualifier)
2336 ++s;
2337 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002338 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002339 fputs("Not enough memory to parse event qualifier",
2340 trace.output);
2341 err = -ENOMEM;
2342 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002343 }
2344 }
2345
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002346 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002347 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002348 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002349 fprintf(trace.output, "%s", bf);
2350 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002351 }
2352
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002353 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002354 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002355 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002356 fprintf(trace.output, "%s", bf);
2357 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002358 }
2359
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002360 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002361 trace.opts.target.system_wide = true;
2362
David Ahern6810fc92013-08-28 22:29:52 -06002363 if (input_name)
2364 err = trace__replay(&trace);
2365 else
2366 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002367
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002368out_close:
2369 if (output_name != NULL)
2370 fclose(trace.output);
2371out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002372 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002373}