blob: 896f27047ed6178fd6aed5566863fb4f4c251e84 [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{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300149 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300150 perf_evsel__delete(evsel);
151}
152
Namhyung Kim96695d42013-11-12 08:51:45 -0300153static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
154{
155 evsel->priv = malloc(sizeof(struct syscall_tp));
156 if (evsel->priv != NULL) {
157 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
158 goto out_delete;
159
160 evsel->handler = handler;
161 return 0;
162 }
163
164 return -ENOMEM;
165
166out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300167 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300168 return -ENOENT;
169}
170
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300171static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300172{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300173 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300174
David Ahern9aca7f12013-12-04 19:41:39 -0700175 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
176 if (evsel == NULL)
177 evsel = perf_evsel__newtp("syscalls", direction);
178
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300179 if (evsel) {
Namhyung Kim96695d42013-11-12 08:51:45 -0300180 if (perf_evsel__init_syscall_tp(evsel, handler))
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300181 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300182 }
183
184 return evsel;
185
186out_delete:
187 perf_evsel__delete_priv(evsel);
188 return NULL;
189}
190
191#define perf_evsel__sc_tp_uint(evsel, name, sample) \
192 ({ struct syscall_tp *fields = evsel->priv; \
193 fields->name.integer(&fields->name, sample); })
194
195#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
196 ({ struct syscall_tp *fields = evsel->priv; \
197 fields->name.pointer(&fields->name, sample); })
198
199static int perf_evlist__add_syscall_newtp(struct perf_evlist *evlist,
200 void *sys_enter_handler,
201 void *sys_exit_handler)
202{
203 int ret = -1;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300204 struct perf_evsel *sys_enter, *sys_exit;
205
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300206 sys_enter = perf_evsel__syscall_newtp("sys_enter", sys_enter_handler);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300207 if (sys_enter == NULL)
208 goto out;
209
210 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
211 goto out_delete_sys_enter;
212
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300213 sys_exit = perf_evsel__syscall_newtp("sys_exit", sys_exit_handler);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300214 if (sys_exit == NULL)
215 goto out_delete_sys_enter;
216
217 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
218 goto out_delete_sys_exit;
219
220 perf_evlist__add(evlist, sys_enter);
221 perf_evlist__add(evlist, sys_exit);
222
223 ret = 0;
224out:
225 return ret;
226
227out_delete_sys_exit:
228 perf_evsel__delete_priv(sys_exit);
229out_delete_sys_enter:
230 perf_evsel__delete_priv(sys_enter);
231 goto out;
232}
233
234
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300235struct syscall_arg {
236 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300237 struct thread *thread;
238 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300239 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300240 u8 idx;
241 u8 mask;
242};
243
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300244struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300245 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300246 int nr_entries;
247 const char **entries;
248};
249
250#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
251 .nr_entries = ARRAY_SIZE(array), \
252 .entries = array, \
253}
254
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300255#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
256 .offset = off, \
257 .nr_entries = ARRAY_SIZE(array), \
258 .entries = array, \
259}
260
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300261static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
262 const char *intfmt,
263 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300264{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300265 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300266 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300267
268 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300269 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300270
271 return scnprintf(bf, size, "%s", sa->entries[idx]);
272}
273
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300274static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
275 struct syscall_arg *arg)
276{
277 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
278}
279
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300280#define SCA_STRARRAY syscall_arg__scnprintf_strarray
281
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300282static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
283 struct syscall_arg *arg)
284{
285 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
286}
287
288#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
289
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300290static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
291 struct syscall_arg *arg);
292
293#define SCA_FD syscall_arg__scnprintf_fd
294
295static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
296 struct syscall_arg *arg)
297{
298 int fd = arg->val;
299
300 if (fd == AT_FDCWD)
301 return scnprintf(bf, size, "CWD");
302
303 return syscall_arg__scnprintf_fd(bf, size, arg);
304}
305
306#define SCA_FDAT syscall_arg__scnprintf_fd_at
307
308static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
309 struct syscall_arg *arg);
310
311#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
312
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300313static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300314 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300315{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300316 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300317}
318
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300319#define SCA_HEX syscall_arg__scnprintf_hex
320
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300321static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300322 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300323{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300324 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300325
326 if (prot == PROT_NONE)
327 return scnprintf(bf, size, "NONE");
328#define P_MMAP_PROT(n) \
329 if (prot & PROT_##n) { \
330 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
331 prot &= ~PROT_##n; \
332 }
333
334 P_MMAP_PROT(EXEC);
335 P_MMAP_PROT(READ);
336 P_MMAP_PROT(WRITE);
337#ifdef PROT_SEM
338 P_MMAP_PROT(SEM);
339#endif
340 P_MMAP_PROT(GROWSDOWN);
341 P_MMAP_PROT(GROWSUP);
342#undef P_MMAP_PROT
343
344 if (prot)
345 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
346
347 return printed;
348}
349
350#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
351
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300352static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300353 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300354{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300355 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300356
357#define P_MMAP_FLAG(n) \
358 if (flags & MAP_##n) { \
359 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
360 flags &= ~MAP_##n; \
361 }
362
363 P_MMAP_FLAG(SHARED);
364 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400365#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300366 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400367#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300368 P_MMAP_FLAG(ANONYMOUS);
369 P_MMAP_FLAG(DENYWRITE);
370 P_MMAP_FLAG(EXECUTABLE);
371 P_MMAP_FLAG(FILE);
372 P_MMAP_FLAG(FIXED);
373 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600374#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300375 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600376#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300377 P_MMAP_FLAG(LOCKED);
378 P_MMAP_FLAG(NONBLOCK);
379 P_MMAP_FLAG(NORESERVE);
380 P_MMAP_FLAG(POPULATE);
381 P_MMAP_FLAG(STACK);
382#ifdef MAP_UNINITIALIZED
383 P_MMAP_FLAG(UNINITIALIZED);
384#endif
385#undef P_MMAP_FLAG
386
387 if (flags)
388 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
389
390 return printed;
391}
392
393#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
394
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300395static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300396 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300397{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300398 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300399
400 switch (behavior) {
401#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
402 P_MADV_BHV(NORMAL);
403 P_MADV_BHV(RANDOM);
404 P_MADV_BHV(SEQUENTIAL);
405 P_MADV_BHV(WILLNEED);
406 P_MADV_BHV(DONTNEED);
407 P_MADV_BHV(REMOVE);
408 P_MADV_BHV(DONTFORK);
409 P_MADV_BHV(DOFORK);
410 P_MADV_BHV(HWPOISON);
411#ifdef MADV_SOFT_OFFLINE
412 P_MADV_BHV(SOFT_OFFLINE);
413#endif
414 P_MADV_BHV(MERGEABLE);
415 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600416#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300417 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600418#endif
419#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300420 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600421#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300422#ifdef MADV_DONTDUMP
423 P_MADV_BHV(DONTDUMP);
424#endif
425#ifdef MADV_DODUMP
426 P_MADV_BHV(DODUMP);
427#endif
428#undef P_MADV_PHV
429 default: break;
430 }
431
432 return scnprintf(bf, size, "%#x", behavior);
433}
434
435#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
436
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300437static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
438 struct syscall_arg *arg)
439{
440 int printed = 0, op = arg->val;
441
442 if (op == 0)
443 return scnprintf(bf, size, "NONE");
444#define P_CMD(cmd) \
445 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
446 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
447 op &= ~LOCK_##cmd; \
448 }
449
450 P_CMD(SH);
451 P_CMD(EX);
452 P_CMD(NB);
453 P_CMD(UN);
454 P_CMD(MAND);
455 P_CMD(RW);
456 P_CMD(READ);
457 P_CMD(WRITE);
458#undef P_OP
459
460 if (op)
461 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
462
463 return printed;
464}
465
466#define SCA_FLOCK syscall_arg__scnprintf_flock
467
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300468static 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 -0300469{
470 enum syscall_futex_args {
471 SCF_UADDR = (1 << 0),
472 SCF_OP = (1 << 1),
473 SCF_VAL = (1 << 2),
474 SCF_TIMEOUT = (1 << 3),
475 SCF_UADDR2 = (1 << 4),
476 SCF_VAL3 = (1 << 5),
477 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300478 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300479 int cmd = op & FUTEX_CMD_MASK;
480 size_t printed = 0;
481
482 switch (cmd) {
483#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300484 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
485 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
486 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
487 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
488 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
489 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300490 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300491 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
492 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
493 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
494 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
495 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300496 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
497 default: printed = scnprintf(bf, size, "%#x", cmd); break;
498 }
499
500 if (op & FUTEX_PRIVATE_FLAG)
501 printed += scnprintf(bf + printed, size - printed, "|PRIV");
502
503 if (op & FUTEX_CLOCK_REALTIME)
504 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
505
506 return printed;
507}
508
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300509#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
510
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300511static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
512static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300513
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300514static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
515static DEFINE_STRARRAY(itimers);
516
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300517static const char *whences[] = { "SET", "CUR", "END",
518#ifdef SEEK_DATA
519"DATA",
520#endif
521#ifdef SEEK_HOLE
522"HOLE",
523#endif
524};
525static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300526
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300527static const char *fcntl_cmds[] = {
528 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
529 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
530 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
531 "F_GETOWNER_UIDS",
532};
533static DEFINE_STRARRAY(fcntl_cmds);
534
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300535static const char *rlimit_resources[] = {
536 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
537 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
538 "RTTIME",
539};
540static DEFINE_STRARRAY(rlimit_resources);
541
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300542static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
543static DEFINE_STRARRAY(sighow);
544
David Ahern4f8c1b72013-09-22 19:45:00 -0600545static const char *clockid[] = {
546 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
547 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
548};
549static DEFINE_STRARRAY(clockid);
550
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300551static const char *socket_families[] = {
552 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
553 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
554 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
555 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
556 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
557 "ALG", "NFC", "VSOCK",
558};
559static DEFINE_STRARRAY(socket_families);
560
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300561#ifndef SOCK_TYPE_MASK
562#define SOCK_TYPE_MASK 0xf
563#endif
564
565static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
566 struct syscall_arg *arg)
567{
568 size_t printed;
569 int type = arg->val,
570 flags = type & ~SOCK_TYPE_MASK;
571
572 type &= SOCK_TYPE_MASK;
573 /*
574 * Can't use a strarray, MIPS may override for ABI reasons.
575 */
576 switch (type) {
577#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
578 P_SK_TYPE(STREAM);
579 P_SK_TYPE(DGRAM);
580 P_SK_TYPE(RAW);
581 P_SK_TYPE(RDM);
582 P_SK_TYPE(SEQPACKET);
583 P_SK_TYPE(DCCP);
584 P_SK_TYPE(PACKET);
585#undef P_SK_TYPE
586 default:
587 printed = scnprintf(bf, size, "%#x", type);
588 }
589
590#define P_SK_FLAG(n) \
591 if (flags & SOCK_##n) { \
592 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
593 flags &= ~SOCK_##n; \
594 }
595
596 P_SK_FLAG(CLOEXEC);
597 P_SK_FLAG(NONBLOCK);
598#undef P_SK_FLAG
599
600 if (flags)
601 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
602
603 return printed;
604}
605
606#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
607
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300608#ifndef MSG_PROBE
609#define MSG_PROBE 0x10
610#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600611#ifndef MSG_WAITFORONE
612#define MSG_WAITFORONE 0x10000
613#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300614#ifndef MSG_SENDPAGE_NOTLAST
615#define MSG_SENDPAGE_NOTLAST 0x20000
616#endif
617#ifndef MSG_FASTOPEN
618#define MSG_FASTOPEN 0x20000000
619#endif
620
621static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
622 struct syscall_arg *arg)
623{
624 int printed = 0, flags = arg->val;
625
626 if (flags == 0)
627 return scnprintf(bf, size, "NONE");
628#define P_MSG_FLAG(n) \
629 if (flags & MSG_##n) { \
630 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
631 flags &= ~MSG_##n; \
632 }
633
634 P_MSG_FLAG(OOB);
635 P_MSG_FLAG(PEEK);
636 P_MSG_FLAG(DONTROUTE);
637 P_MSG_FLAG(TRYHARD);
638 P_MSG_FLAG(CTRUNC);
639 P_MSG_FLAG(PROBE);
640 P_MSG_FLAG(TRUNC);
641 P_MSG_FLAG(DONTWAIT);
642 P_MSG_FLAG(EOR);
643 P_MSG_FLAG(WAITALL);
644 P_MSG_FLAG(FIN);
645 P_MSG_FLAG(SYN);
646 P_MSG_FLAG(CONFIRM);
647 P_MSG_FLAG(RST);
648 P_MSG_FLAG(ERRQUEUE);
649 P_MSG_FLAG(NOSIGNAL);
650 P_MSG_FLAG(MORE);
651 P_MSG_FLAG(WAITFORONE);
652 P_MSG_FLAG(SENDPAGE_NOTLAST);
653 P_MSG_FLAG(FASTOPEN);
654 P_MSG_FLAG(CMSG_CLOEXEC);
655#undef P_MSG_FLAG
656
657 if (flags)
658 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
659
660 return printed;
661}
662
663#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
664
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300665static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
666 struct syscall_arg *arg)
667{
668 size_t printed = 0;
669 int mode = arg->val;
670
671 if (mode == F_OK) /* 0 */
672 return scnprintf(bf, size, "F");
673#define P_MODE(n) \
674 if (mode & n##_OK) { \
675 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
676 mode &= ~n##_OK; \
677 }
678
679 P_MODE(R);
680 P_MODE(W);
681 P_MODE(X);
682#undef P_MODE
683
684 if (mode)
685 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
686
687 return printed;
688}
689
690#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
691
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300692static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300693 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300694{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300695 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300696
697 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300698 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300699
700 if (flags == 0)
701 return scnprintf(bf, size, "RDONLY");
702#define P_FLAG(n) \
703 if (flags & O_##n) { \
704 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
705 flags &= ~O_##n; \
706 }
707
708 P_FLAG(APPEND);
709 P_FLAG(ASYNC);
710 P_FLAG(CLOEXEC);
711 P_FLAG(CREAT);
712 P_FLAG(DIRECT);
713 P_FLAG(DIRECTORY);
714 P_FLAG(EXCL);
715 P_FLAG(LARGEFILE);
716 P_FLAG(NOATIME);
717 P_FLAG(NOCTTY);
718#ifdef O_NONBLOCK
719 P_FLAG(NONBLOCK);
720#elif O_NDELAY
721 P_FLAG(NDELAY);
722#endif
723#ifdef O_PATH
724 P_FLAG(PATH);
725#endif
726 P_FLAG(RDWR);
727#ifdef O_DSYNC
728 if ((flags & O_SYNC) == O_SYNC)
729 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
730 else {
731 P_FLAG(DSYNC);
732 }
733#else
734 P_FLAG(SYNC);
735#endif
736 P_FLAG(TRUNC);
737 P_FLAG(WRONLY);
738#undef P_FLAG
739
740 if (flags)
741 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
742
743 return printed;
744}
745
746#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
747
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300748static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
749 struct syscall_arg *arg)
750{
751 int printed = 0, flags = arg->val;
752
753 if (flags == 0)
754 return scnprintf(bf, size, "NONE");
755#define P_FLAG(n) \
756 if (flags & EFD_##n) { \
757 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
758 flags &= ~EFD_##n; \
759 }
760
761 P_FLAG(SEMAPHORE);
762 P_FLAG(CLOEXEC);
763 P_FLAG(NONBLOCK);
764#undef P_FLAG
765
766 if (flags)
767 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
768
769 return printed;
770}
771
772#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
773
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300774static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
775 struct syscall_arg *arg)
776{
777 int printed = 0, flags = arg->val;
778
779#define P_FLAG(n) \
780 if (flags & O_##n) { \
781 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
782 flags &= ~O_##n; \
783 }
784
785 P_FLAG(CLOEXEC);
786 P_FLAG(NONBLOCK);
787#undef P_FLAG
788
789 if (flags)
790 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
791
792 return printed;
793}
794
795#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
796
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300797static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
798{
799 int sig = arg->val;
800
801 switch (sig) {
802#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
803 P_SIGNUM(HUP);
804 P_SIGNUM(INT);
805 P_SIGNUM(QUIT);
806 P_SIGNUM(ILL);
807 P_SIGNUM(TRAP);
808 P_SIGNUM(ABRT);
809 P_SIGNUM(BUS);
810 P_SIGNUM(FPE);
811 P_SIGNUM(KILL);
812 P_SIGNUM(USR1);
813 P_SIGNUM(SEGV);
814 P_SIGNUM(USR2);
815 P_SIGNUM(PIPE);
816 P_SIGNUM(ALRM);
817 P_SIGNUM(TERM);
818 P_SIGNUM(STKFLT);
819 P_SIGNUM(CHLD);
820 P_SIGNUM(CONT);
821 P_SIGNUM(STOP);
822 P_SIGNUM(TSTP);
823 P_SIGNUM(TTIN);
824 P_SIGNUM(TTOU);
825 P_SIGNUM(URG);
826 P_SIGNUM(XCPU);
827 P_SIGNUM(XFSZ);
828 P_SIGNUM(VTALRM);
829 P_SIGNUM(PROF);
830 P_SIGNUM(WINCH);
831 P_SIGNUM(IO);
832 P_SIGNUM(PWR);
833 P_SIGNUM(SYS);
834 default: break;
835 }
836
837 return scnprintf(bf, size, "%#x", sig);
838}
839
840#define SCA_SIGNUM syscall_arg__scnprintf_signum
841
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300842#define TCGETS 0x5401
843
844static const char *tioctls[] = {
845 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
846 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
847 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
848 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
849 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
850 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
851 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
852 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
853 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
854 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
855 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
856 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
857 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
858 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
859 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
860};
861
862static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
863
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300864#define STRARRAY(arg, name, array) \
865 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
866 .arg_parm = { [arg] = &strarray__##array, }
867
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300868static struct syscall_fmt {
869 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300870 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300871 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300872 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300873 bool errmsg;
874 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300875 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300876} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300877 { .name = "access", .errmsg = true,
878 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300879 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300880 { .name = "brk", .hexret = true,
881 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600882 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300883 { .name = "close", .errmsg = true,
884 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300885 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300886 { .name = "dup", .errmsg = true,
887 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
888 { .name = "dup2", .errmsg = true,
889 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
890 { .name = "dup3", .errmsg = true,
891 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300892 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300893 { .name = "eventfd2", .errmsg = true,
894 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300895 { .name = "faccessat", .errmsg = true,
896 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
897 { .name = "fadvise64", .errmsg = true,
898 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
899 { .name = "fallocate", .errmsg = true,
900 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
901 { .name = "fchdir", .errmsg = true,
902 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
903 { .name = "fchmod", .errmsg = true,
904 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
905 { .name = "fchmodat", .errmsg = true,
906 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
907 { .name = "fchown", .errmsg = true,
908 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
909 { .name = "fchownat", .errmsg = true,
910 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
911 { .name = "fcntl", .errmsg = true,
912 .arg_scnprintf = { [0] = SCA_FD, /* fd */
913 [1] = SCA_STRARRAY, /* cmd */ },
914 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
915 { .name = "fdatasync", .errmsg = true,
916 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300917 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300918 .arg_scnprintf = { [0] = SCA_FD, /* fd */
919 [1] = SCA_FLOCK, /* cmd */ }, },
920 { .name = "fsetxattr", .errmsg = true,
921 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
922 { .name = "fstat", .errmsg = true, .alias = "newfstat",
923 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
924 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
925 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
926 { .name = "fstatfs", .errmsg = true,
927 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
928 { .name = "fsync", .errmsg = true,
929 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
930 { .name = "ftruncate", .errmsg = true,
931 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300932 { .name = "futex", .errmsg = true,
933 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300934 { .name = "futimesat", .errmsg = true,
935 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
936 { .name = "getdents", .errmsg = true,
937 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
938 { .name = "getdents64", .errmsg = true,
939 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300940 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
941 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300942 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300943 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300944 [1] = SCA_STRHEXARRAY, /* cmd */
945 [2] = SCA_HEX, /* arg */ },
946 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300947 { .name = "kill", .errmsg = true,
948 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300949 { .name = "linkat", .errmsg = true,
950 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
951 { .name = "lseek", .errmsg = true,
952 .arg_scnprintf = { [0] = SCA_FD, /* fd */
953 [2] = SCA_STRARRAY, /* whence */ },
954 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300955 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300956 { .name = "madvise", .errmsg = true,
957 .arg_scnprintf = { [0] = SCA_HEX, /* start */
958 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300959 { .name = "mkdirat", .errmsg = true,
960 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
961 { .name = "mknodat", .errmsg = true,
962 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300963 { .name = "mlock", .errmsg = true,
964 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
965 { .name = "mlockall", .errmsg = true,
966 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300967 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300968 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300969 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +0900970 [3] = SCA_MMAP_FLAGS, /* flags */
971 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300972 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300973 .arg_scnprintf = { [0] = SCA_HEX, /* start */
974 [2] = SCA_MMAP_PROT, /* prot */ }, },
975 { .name = "mremap", .hexret = true,
976 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
977 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300978 { .name = "munlock", .errmsg = true,
979 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300980 { .name = "munmap", .errmsg = true,
981 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300982 { .name = "name_to_handle_at", .errmsg = true,
983 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
984 { .name = "newfstatat", .errmsg = true,
985 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300986 { .name = "open", .errmsg = true,
987 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300988 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300989 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
990 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300991 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300992 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
993 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300994 { .name = "pipe2", .errmsg = true,
995 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300996 { .name = "poll", .errmsg = true, .timeout = true, },
997 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300998 { .name = "pread", .errmsg = true, .alias = "pread64",
999 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1000 { .name = "preadv", .errmsg = true, .alias = "pread",
1001 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001002 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001003 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
1004 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1005 { .name = "pwritev", .errmsg = true,
1006 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1007 { .name = "read", .errmsg = true,
1008 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1009 { .name = "readlinkat", .errmsg = true,
1010 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1011 { .name = "readv", .errmsg = true,
1012 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001013 { .name = "recvfrom", .errmsg = true,
1014 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1015 { .name = "recvmmsg", .errmsg = true,
1016 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1017 { .name = "recvmsg", .errmsg = true,
1018 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001019 { .name = "renameat", .errmsg = true,
1020 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001021 { .name = "rt_sigaction", .errmsg = true,
1022 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001023 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001024 { .name = "rt_sigqueueinfo", .errmsg = true,
1025 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1026 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1027 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001028 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001029 { .name = "sendmmsg", .errmsg = true,
1030 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1031 { .name = "sendmsg", .errmsg = true,
1032 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
1033 { .name = "sendto", .errmsg = true,
1034 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001035 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1036 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001037 { .name = "shutdown", .errmsg = true,
1038 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001039 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001040 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1041 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001042 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001043 { .name = "socketpair", .errmsg = true,
1044 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1045 [1] = SCA_SK_TYPE, /* type */ },
1046 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001047 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001048 { .name = "symlinkat", .errmsg = true,
1049 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001050 { .name = "tgkill", .errmsg = true,
1051 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1052 { .name = "tkill", .errmsg = true,
1053 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001054 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001055 { .name = "unlinkat", .errmsg = true,
1056 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1057 { .name = "utimensat", .errmsg = true,
1058 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
1059 { .name = "write", .errmsg = true,
1060 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1061 { .name = "writev", .errmsg = true,
1062 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001063};
1064
1065static int syscall_fmt__cmp(const void *name, const void *fmtp)
1066{
1067 const struct syscall_fmt *fmt = fmtp;
1068 return strcmp(name, fmt->name);
1069}
1070
1071static struct syscall_fmt *syscall_fmt__find(const char *name)
1072{
1073 const int nmemb = ARRAY_SIZE(syscall_fmts);
1074 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1075}
1076
1077struct syscall {
1078 struct event_format *tp_format;
1079 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001080 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001081 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001082 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001083 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001084};
1085
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001086static size_t fprintf_duration(unsigned long t, FILE *fp)
1087{
1088 double duration = (double)t / NSEC_PER_MSEC;
1089 size_t printed = fprintf(fp, "(");
1090
1091 if (duration >= 1.0)
1092 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1093 else if (duration >= 0.01)
1094 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1095 else
1096 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001097 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001098}
1099
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001100struct thread_trace {
1101 u64 entry_time;
1102 u64 exit_time;
1103 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001104 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001105 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001106 double runtime_ms;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001107 struct {
1108 int max;
1109 char **table;
1110 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001111
1112 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001113};
1114
1115static struct thread_trace *thread_trace__new(void)
1116{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001117 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1118
1119 if (ttrace)
1120 ttrace->paths.max = -1;
1121
David Ahernbf2575c2013-10-08 21:26:53 -06001122 ttrace->syscall_stats = intlist__new(NULL);
1123
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001124 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001125}
1126
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001127static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001128{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001129 struct thread_trace *ttrace;
1130
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001131 if (thread == NULL)
1132 goto fail;
1133
1134 if (thread->priv == NULL)
1135 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001136
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001137 if (thread->priv == NULL)
1138 goto fail;
1139
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001140 ttrace = thread->priv;
1141 ++ttrace->nr_events;
1142
1143 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001144fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001145 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001146 "WARNING: not enough memory, dropping samples!\n");
1147 return NULL;
1148}
1149
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001150struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001151 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001152 struct {
1153 int machine;
1154 int open_id;
1155 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001156 struct {
1157 int max;
1158 struct syscall *table;
1159 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001160 struct record_opts opts;
David Ahern8fb598e2013-09-28 13:13:00 -06001161 struct machine *host;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001162 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001163 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001164 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001165 struct strlist *ev_qualifier;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001166 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -06001167 struct intlist *tid_list;
1168 struct intlist *pid_list;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001169 double duration_filter;
1170 double runtime_ms;
1171 struct {
1172 u64 vfs_getname,
1173 proc_getname;
1174 } stats;
1175 bool not_ev_qualifier;
1176 bool live;
1177 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001178 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001179 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001180 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001181 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001182 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001183 bool show_tool_stats;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001184};
1185
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001186static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001187{
1188 struct thread_trace *ttrace = thread->priv;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001189
1190 if (fd > ttrace->paths.max) {
1191 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1192
1193 if (npath == NULL)
1194 return -1;
1195
1196 if (ttrace->paths.max != -1) {
1197 memset(npath + ttrace->paths.max + 1, 0,
1198 (fd - ttrace->paths.max) * sizeof(char *));
1199 } else {
1200 memset(npath, 0, (fd + 1) * sizeof(char *));
1201 }
1202
1203 ttrace->paths.table = npath;
1204 ttrace->paths.max = fd;
1205 }
1206
1207 ttrace->paths.table[fd] = strdup(pathname);
1208
1209 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1210}
1211
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001212static int thread__read_fd_path(struct thread *thread, int fd)
1213{
1214 char linkname[PATH_MAX], pathname[PATH_MAX];
1215 struct stat st;
1216 int ret;
1217
1218 if (thread->pid_ == thread->tid) {
1219 scnprintf(linkname, sizeof(linkname),
1220 "/proc/%d/fd/%d", thread->pid_, fd);
1221 } else {
1222 scnprintf(linkname, sizeof(linkname),
1223 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1224 }
1225
1226 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1227 return -1;
1228
1229 ret = readlink(linkname, pathname, sizeof(pathname));
1230
1231 if (ret < 0 || ret > st.st_size)
1232 return -1;
1233
1234 pathname[ret] = '\0';
1235 return trace__set_fd_pathname(thread, fd, pathname);
1236}
1237
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001238static const char *thread__fd_path(struct thread *thread, int fd,
1239 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001240{
1241 struct thread_trace *ttrace = thread->priv;
1242
1243 if (ttrace == NULL)
1244 return NULL;
1245
1246 if (fd < 0)
1247 return NULL;
1248
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001249 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL))
1250 if (!trace->live)
1251 return NULL;
1252 ++trace->stats.proc_getname;
1253 if (thread__read_fd_path(thread, fd)) {
1254 return NULL;
1255 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001256
1257 return ttrace->paths.table[fd];
1258}
1259
1260static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1261 struct syscall_arg *arg)
1262{
1263 int fd = arg->val;
1264 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001265 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001266
1267 if (path)
1268 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1269
1270 return printed;
1271}
1272
1273static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1274 struct syscall_arg *arg)
1275{
1276 int fd = arg->val;
1277 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1278 struct thread_trace *ttrace = arg->thread->priv;
1279
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001280 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1281 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001282
1283 return printed;
1284}
1285
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001286static bool trace__filter_duration(struct trace *trace, double t)
1287{
1288 return t < (trace->duration_filter * NSEC_PER_MSEC);
1289}
1290
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001291static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1292{
1293 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1294
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001295 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001296}
1297
Namhyung Kimf15eb532012-10-05 14:02:16 +09001298static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001299static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001300
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001301static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001302{
1303 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001304 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001305}
1306
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001307static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001308 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001309{
1310 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001311 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001312
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001313 if (trace->multiple_threads) {
1314 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001315 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001316 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001317 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001318
1319 return printed;
1320}
1321
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001322static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001323 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001324{
1325 int ret = 0;
1326
1327 switch (event->header.type) {
1328 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001329 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001330 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001331 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001332 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001333 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001334 break;
1335 }
1336
1337 return ret;
1338}
1339
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001340static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001341 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001342 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001343 struct machine *machine)
1344{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001345 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001346 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001347}
1348
1349static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1350{
1351 int err = symbol__init();
1352
1353 if (err)
1354 return err;
1355
David Ahern8fb598e2013-09-28 13:13:00 -06001356 trace->host = machine__new_host();
1357 if (trace->host == NULL)
1358 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001359
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001360 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
1361 evlist->threads, trace__tool_process, false);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001362 if (err)
1363 symbol__exit();
1364
1365 return err;
1366}
1367
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001368static int syscall__set_arg_fmts(struct syscall *sc)
1369{
1370 struct format_field *field;
1371 int idx = 0;
1372
1373 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1374 if (sc->arg_scnprintf == NULL)
1375 return -1;
1376
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001377 if (sc->fmt)
1378 sc->arg_parm = sc->fmt->arg_parm;
1379
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001380 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001381 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1382 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1383 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001384 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1385 ++idx;
1386 }
1387
1388 return 0;
1389}
1390
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001391static int trace__read_syscall_info(struct trace *trace, int id)
1392{
1393 char tp_name[128];
1394 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001395 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001396
1397 if (name == NULL)
1398 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001399
1400 if (id > trace->syscalls.max) {
1401 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1402
1403 if (nsyscalls == NULL)
1404 return -1;
1405
1406 if (trace->syscalls.max != -1) {
1407 memset(nsyscalls + trace->syscalls.max + 1, 0,
1408 (id - trace->syscalls.max) * sizeof(*sc));
1409 } else {
1410 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1411 }
1412
1413 trace->syscalls.table = nsyscalls;
1414 trace->syscalls.max = id;
1415 }
1416
1417 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001418 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001419
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001420 if (trace->ev_qualifier) {
1421 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1422
1423 if (!(in ^ trace->not_ev_qualifier)) {
1424 sc->filtered = true;
1425 /*
1426 * No need to do read tracepoint information since this will be
1427 * filtered out.
1428 */
1429 return 0;
1430 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001431 }
1432
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001433 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001434
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001435 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001436 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001437
1438 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1439 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001440 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001441 }
1442
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001443 if (sc->tp_format == NULL)
1444 return -1;
1445
1446 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001447}
1448
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001449static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001450 unsigned long *args, struct trace *trace,
1451 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001452{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001453 size_t printed = 0;
1454
1455 if (sc->tp_format != NULL) {
1456 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001457 u8 bit = 1;
1458 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001459 .idx = 0,
1460 .mask = 0,
1461 .trace = trace,
1462 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001463 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001464
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001465 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001466 field = field->next, ++arg.idx, bit <<= 1) {
1467 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001468 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001469 /*
1470 * Suppress this argument if its value is zero and
1471 * and we don't have a string associated in an
1472 * strarray for it.
1473 */
1474 if (args[arg.idx] == 0 &&
1475 !(sc->arg_scnprintf &&
1476 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1477 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001478 continue;
1479
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001480 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001481 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001482 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1483 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001484 if (sc->arg_parm)
1485 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001486 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1487 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001488 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001489 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001490 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001491 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001492 }
1493 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001494 int i = 0;
1495
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001496 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001497 printed += scnprintf(bf + printed, size - printed,
1498 "%sarg%d: %ld",
1499 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001500 ++i;
1501 }
1502 }
1503
1504 return printed;
1505}
1506
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001507typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1508 struct perf_sample *sample);
1509
1510static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001511 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001512{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001513
1514 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001515
1516 /*
1517 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1518 * before that, leaving at a higher verbosity level till that is
1519 * explained. Reproduced with plain ftrace with:
1520 *
1521 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1522 * grep "NR -1 " /t/trace_pipe
1523 *
1524 * After generating some load on the machine.
1525 */
1526 if (verbose > 1) {
1527 static u64 n;
1528 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1529 id, perf_evsel__name(evsel), ++n);
1530 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001531 return NULL;
1532 }
1533
1534 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1535 trace__read_syscall_info(trace, id))
1536 goto out_cant_read;
1537
1538 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1539 goto out_cant_read;
1540
1541 return &trace->syscalls.table[id];
1542
1543out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001544 if (verbose) {
1545 fprintf(trace->output, "Problems reading syscall %d", id);
1546 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1547 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1548 fputs(" information\n", trace->output);
1549 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001550 return NULL;
1551}
1552
David Ahernbf2575c2013-10-08 21:26:53 -06001553static void thread__update_stats(struct thread_trace *ttrace,
1554 int id, struct perf_sample *sample)
1555{
1556 struct int_node *inode;
1557 struct stats *stats;
1558 u64 duration = 0;
1559
1560 inode = intlist__findnew(ttrace->syscall_stats, id);
1561 if (inode == NULL)
1562 return;
1563
1564 stats = inode->priv;
1565 if (stats == NULL) {
1566 stats = malloc(sizeof(struct stats));
1567 if (stats == NULL)
1568 return;
1569 init_stats(stats);
1570 inode->priv = stats;
1571 }
1572
1573 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1574 duration = sample->time - ttrace->entry_time;
1575
1576 update_stats(stats, duration);
1577}
1578
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001579static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1580 struct perf_sample *sample)
1581{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001582 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001583 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001584 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001585 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001586 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001587 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001588 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001589
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001590 if (sc == NULL)
1591 return -1;
1592
1593 if (sc->filtered)
1594 return 0;
1595
David Ahern8fb598e2013-09-28 13:13:00 -06001596 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001597 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001598 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001599 return -1;
1600
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001601 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001602 ttrace = thread->priv;
1603
1604 if (ttrace->entry_str == NULL) {
1605 ttrace->entry_str = malloc(1024);
1606 if (!ttrace->entry_str)
1607 return -1;
1608 }
1609
1610 ttrace->entry_time = sample->time;
1611 msg = ttrace->entry_str;
1612 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1613
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001614 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1615 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001616
1617 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001618 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001619 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1620 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001621 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001622 } else
1623 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001624
1625 return 0;
1626}
1627
1628static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1629 struct perf_sample *sample)
1630{
1631 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001632 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001633 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001634 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001635 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001636 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001637
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001638 if (sc == NULL)
1639 return -1;
1640
1641 if (sc->filtered)
1642 return 0;
1643
David Ahern8fb598e2013-09-28 13:13:00 -06001644 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001645 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001646 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001647 return -1;
1648
David Ahernbf2575c2013-10-08 21:26:53 -06001649 if (trace->summary)
1650 thread__update_stats(ttrace, id, sample);
1651
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001652 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001653
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001654 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1655 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1656 trace->last_vfs_getname = NULL;
1657 ++trace->stats.vfs_getname;
1658 }
1659
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001660 ttrace = thread->priv;
1661
1662 ttrace->exit_time = sample->time;
1663
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001664 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001665 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001666 if (trace__filter_duration(trace, duration))
1667 goto out;
1668 } else if (trace->duration_filter)
1669 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001670
David Ahernfd2eaba2013-11-12 09:31:15 -07001671 if (trace->summary_only)
1672 goto out;
1673
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001674 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001675
1676 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001677 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001678 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001679 fprintf(trace->output, " ... [");
1680 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1681 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001682 }
1683
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001684 if (sc->fmt == NULL) {
1685signed_print:
1686 fprintf(trace->output, ") = %d", ret);
1687 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001688 char bf[256];
1689 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1690 *e = audit_errno_to_name(-ret);
1691
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001692 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001693 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001694 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001695 else if (sc->fmt->hexret)
1696 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001697 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001698 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001699
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001700 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001701out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001702 ttrace->entry_pending = false;
1703
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001704 return 0;
1705}
1706
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001707static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1708 struct perf_sample *sample)
1709{
1710 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1711 return 0;
1712}
1713
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001714static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1715 struct perf_sample *sample)
1716{
1717 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1718 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001719 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001720 sample->pid,
1721 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001722 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001723
1724 if (ttrace == NULL)
1725 goto out_dump;
1726
1727 ttrace->runtime_ms += runtime_ms;
1728 trace->runtime_ms += runtime_ms;
1729 return 0;
1730
1731out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001732 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001733 evsel->name,
1734 perf_evsel__strval(evsel, sample, "comm"),
1735 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1736 runtime,
1737 perf_evsel__intval(evsel, sample, "vruntime"));
1738 return 0;
1739}
1740
David Ahernbdc89662013-08-28 22:29:53 -06001741static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1742{
1743 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1744 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1745 return false;
1746
1747 if (trace->pid_list || trace->tid_list)
1748 return true;
1749
1750 return false;
1751}
1752
David Ahern6810fc92013-08-28 22:29:52 -06001753static int trace__process_sample(struct perf_tool *tool,
1754 union perf_event *event __maybe_unused,
1755 struct perf_sample *sample,
1756 struct perf_evsel *evsel,
1757 struct machine *machine __maybe_unused)
1758{
1759 struct trace *trace = container_of(tool, struct trace, tool);
1760 int err = 0;
1761
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001762 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001763
David Ahernbdc89662013-08-28 22:29:53 -06001764 if (skip_sample(trace, sample))
1765 return 0;
1766
David Ahern4bb09192013-09-04 12:37:43 -06001767 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001768 trace->base_time = sample->time;
1769
David Ahern31605652013-12-04 19:41:41 -07001770 if (handler) {
1771 ++trace->nr_events;
David Ahern6810fc92013-08-28 22:29:52 -06001772 handler(trace, evsel, sample);
David Ahern31605652013-12-04 19:41:41 -07001773 }
David Ahern6810fc92013-08-28 22:29:52 -06001774
1775 return err;
1776}
1777
David Ahernbdc89662013-08-28 22:29:53 -06001778static int parse_target_str(struct trace *trace)
1779{
1780 if (trace->opts.target.pid) {
1781 trace->pid_list = intlist__new(trace->opts.target.pid);
1782 if (trace->pid_list == NULL) {
1783 pr_err("Error parsing process id string\n");
1784 return -EINVAL;
1785 }
1786 }
1787
1788 if (trace->opts.target.tid) {
1789 trace->tid_list = intlist__new(trace->opts.target.tid);
1790 if (trace->tid_list == NULL) {
1791 pr_err("Error parsing thread id string\n");
1792 return -EINVAL;
1793 }
1794 }
1795
1796 return 0;
1797}
1798
David Ahern5e2485b2013-09-28 13:13:01 -06001799static int trace__record(int argc, const char **argv)
1800{
1801 unsigned int rec_argc, i, j;
1802 const char **rec_argv;
1803 const char * const record_args[] = {
1804 "record",
1805 "-R",
1806 "-m", "1024",
1807 "-c", "1",
David Ahern9aca7f12013-12-04 19:41:39 -07001808 "-e",
David Ahern5e2485b2013-09-28 13:13:01 -06001809 };
1810
David Ahern9aca7f12013-12-04 19:41:39 -07001811 /* +1 is for the event string below */
1812 rec_argc = ARRAY_SIZE(record_args) + 1 + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06001813 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1814
1815 if (rec_argv == NULL)
1816 return -ENOMEM;
1817
1818 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1819 rec_argv[i] = record_args[i];
1820
David Ahern9aca7f12013-12-04 19:41:39 -07001821 /* event string may be different for older kernels - e.g., RHEL6 */
1822 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
1823 rec_argv[i] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
1824 else if (is_valid_tracepoint("syscalls:sys_enter"))
1825 rec_argv[i] = "syscalls:sys_enter,syscalls:sys_exit";
1826 else {
1827 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
1828 return -1;
1829 }
1830 i++;
1831
David Ahern5e2485b2013-09-28 13:13:01 -06001832 for (j = 0; j < (unsigned int)argc; j++, i++)
1833 rec_argv[i] = argv[j];
1834
1835 return cmd_record(i, rec_argv, NULL);
1836}
1837
David Ahernbf2575c2013-10-08 21:26:53 -06001838static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
1839
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001840static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
1841{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03001842 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001843 if (evsel == NULL)
1844 return;
1845
1846 if (perf_evsel__field(evsel, "pathname") == NULL) {
1847 perf_evsel__delete(evsel);
1848 return;
1849 }
1850
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001851 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001852 perf_evlist__add(evlist, evsel);
1853}
1854
Namhyung Kimf15eb532012-10-05 14:02:16 +09001855static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001856{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001857 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001858 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001859 int err = -1, i;
1860 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001861 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001862
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001863 trace->live = true;
1864
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001865 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001866 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001867 goto out;
1868 }
1869
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001870 if (perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, trace__sys_exit))
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301871 goto out_error_tp;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001872
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001873 perf_evlist__add_vfs_getname(evlist);
1874
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001875 if (trace->sched &&
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301876 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1877 trace__sched_stat_runtime))
1878 goto out_error_tp;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001879
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001880 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1881 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001882 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001883 goto out_delete_evlist;
1884 }
1885
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001886 err = trace__symbols_init(trace, evlist);
1887 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001888 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03001889 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001890 }
1891
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001892 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001893
Namhyung Kimf15eb532012-10-05 14:02:16 +09001894 signal(SIGCHLD, sig_handler);
1895 signal(SIGINT, sig_handler);
1896
1897 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001898 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03001899 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001900 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001901 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03001902 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001903 }
1904 }
1905
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001906 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03001907 if (err < 0)
1908 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001909
Jiri Olsaf8850372013-11-28 17:57:22 +01001910 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001911 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001912 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Arnaldo Carvalho de Melof26e1c72014-01-03 16:54:12 -03001913 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001914 }
1915
1916 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001917
1918 if (forks)
1919 perf_evlist__start_workload(evlist);
1920
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001921 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001922again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001923 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001924
1925 for (i = 0; i < evlist->nr_mmaps; i++) {
1926 union perf_event *event;
1927
1928 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1929 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001930 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001931 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001932
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001933 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001934
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001935 err = perf_evlist__parse_sample(evlist, event, &sample);
1936 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001937 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001938 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001939 }
1940
David Ahern4bb09192013-09-04 12:37:43 -06001941 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001942 trace->base_time = sample.time;
1943
1944 if (type != PERF_RECORD_SAMPLE) {
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001945 trace__process_event(trace, trace->host, event, &sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001946 continue;
1947 }
1948
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001949 evsel = perf_evlist__id2evsel(evlist, sample.id);
1950 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001951 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001952 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001953 }
1954
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001955 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001956 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 -03001957 perf_evsel__name(evsel), sample.tid,
1958 sample.cpu, sample.raw_size);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001959 goto next_event;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001960 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001961
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001962 handler = evsel->handler;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001963 handler(trace, evsel, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001964next_event:
1965 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001966
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001967 if (interrupted)
1968 goto out_disable;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001969 }
1970 }
1971
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001972 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001973 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001974
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001975 if (poll(evlist->pollfd, evlist->nr_fds, timeout) > 0)
1976 goto again;
1977 } else {
1978 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001979 }
1980
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001981out_disable:
1982 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001983
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001984 if (!err) {
1985 if (trace->summary)
1986 trace__fprintf_thread_summary(trace, trace->output);
1987
1988 if (trace->show_tool_stats) {
1989 fprintf(trace->output, "Stats:\n "
1990 " vfs_getname : %" PRIu64 "\n"
1991 " proc_getname: %" PRIu64 "\n",
1992 trace->stats.vfs_getname,
1993 trace->stats.proc_getname);
1994 }
1995 }
David Ahernbf2575c2013-10-08 21:26:53 -06001996
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001997out_delete_evlist:
1998 perf_evlist__delete(evlist);
1999out:
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002000 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002001 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002002{
2003 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002004
2005out_error_tp:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002006 perf_evlist__strerror_tp(evlist, errno, errbuf, sizeof(errbuf));
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002007 goto out_error;
2008
2009out_error_open:
2010 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2011
2012out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002013 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302014 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002015}
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002016}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002017
David Ahern6810fc92013-08-28 22:29:52 -06002018static int trace__replay(struct trace *trace)
2019{
2020 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002021 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002022 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002023 struct perf_data_file file = {
2024 .path = input_name,
2025 .mode = PERF_DATA_MODE_READ,
2026 };
David Ahern6810fc92013-08-28 22:29:52 -06002027 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002028 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002029 int err = -1;
2030
2031 trace->tool.sample = trace__process_sample;
2032 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002033 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002034 trace->tool.comm = perf_event__process_comm;
2035 trace->tool.exit = perf_event__process_exit;
2036 trace->tool.fork = perf_event__process_fork;
2037 trace->tool.attr = perf_event__process_attr;
2038 trace->tool.tracing_data = perf_event__process_tracing_data;
2039 trace->tool.build_id = perf_event__process_build_id;
2040
2041 trace->tool.ordered_samples = true;
2042 trace->tool.ordering_requires_timestamps = true;
2043
2044 /* add tid to output */
2045 trace->multiple_threads = true;
2046
2047 if (symbol__init() < 0)
2048 return -1;
2049
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002050 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002051 if (session == NULL)
2052 return -ENOMEM;
2053
David Ahern8fb598e2013-09-28 13:13:00 -06002054 trace->host = &session->machines.host;
2055
David Ahern6810fc92013-08-28 22:29:52 -06002056 err = perf_session__set_tracepoints_handlers(session, handlers);
2057 if (err)
2058 goto out;
2059
Namhyung Kim003824e2013-11-12 15:25:00 +09002060 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2061 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002062 /* older kernels have syscalls tp versus raw_syscalls */
2063 if (evsel == NULL)
2064 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2065 "syscalls:sys_enter");
Namhyung Kim003824e2013-11-12 15:25:00 +09002066 if (evsel == NULL) {
2067 pr_err("Data file does not have raw_syscalls:sys_enter event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002068 goto out;
2069 }
2070
Namhyung Kim003824e2013-11-12 15:25:00 +09002071 if (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2072 perf_evsel__init_sc_tp_ptr_field(evsel, args)) {
2073 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2074 goto out;
2075 }
2076
2077 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2078 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002079 if (evsel == NULL)
2080 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2081 "syscalls:sys_exit");
Namhyung Kim003824e2013-11-12 15:25:00 +09002082 if (evsel == NULL) {
2083 pr_err("Data file does not have raw_syscalls:sys_exit event\n");
2084 goto out;
2085 }
2086
2087 if (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2088 perf_evsel__init_sc_tp_uint_field(evsel, ret)) {
2089 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002090 goto out;
2091 }
2092
David Ahernbdc89662013-08-28 22:29:53 -06002093 err = parse_target_str(trace);
2094 if (err != 0)
2095 goto out;
2096
David Ahern6810fc92013-08-28 22:29:52 -06002097 setup_pager();
2098
2099 err = perf_session__process_events(session, &trace->tool);
2100 if (err)
2101 pr_err("Failed to process events, error %d", err);
2102
David Ahernbf2575c2013-10-08 21:26:53 -06002103 else if (trace->summary)
2104 trace__fprintf_thread_summary(trace, trace->output);
2105
David Ahern6810fc92013-08-28 22:29:52 -06002106out:
2107 perf_session__delete(session);
2108
2109 return err;
2110}
2111
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002112static size_t trace__fprintf_threads_header(FILE *fp)
2113{
2114 size_t printed;
2115
Pekka Enberg99ff7152013-11-12 16:42:14 +02002116 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002117
2118 return printed;
2119}
2120
2121static size_t thread__dump_stats(struct thread_trace *ttrace,
2122 struct trace *trace, FILE *fp)
2123{
2124 struct stats *stats;
2125 size_t printed = 0;
2126 struct syscall *sc;
2127 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2128
2129 if (inode == NULL)
2130 return 0;
2131
2132 printed += fprintf(fp, "\n");
2133
Pekka Enberg27a778b2013-11-13 14:21:48 +02002134 printed += fprintf(fp, " syscall calls min avg max stddev\n");
2135 printed += fprintf(fp, " (msec) (msec) (msec) (%%)\n");
2136 printed += fprintf(fp, " --------------- -------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002137
David Ahernbf2575c2013-10-08 21:26:53 -06002138 /* each int_node is a syscall */
2139 while (inode) {
2140 stats = inode->priv;
2141 if (stats) {
2142 double min = (double)(stats->min) / NSEC_PER_MSEC;
2143 double max = (double)(stats->max) / NSEC_PER_MSEC;
2144 double avg = avg_stats(stats);
2145 double pct;
2146 u64 n = (u64) stats->n;
2147
2148 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2149 avg /= NSEC_PER_MSEC;
2150
2151 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002152 printed += fprintf(fp, " %-15s", sc->name);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002153 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f",
Pekka Enberg7f7a4132013-11-12 16:10:10 +02002154 n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002155 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002156 }
2157
2158 inode = intlist__next(inode);
2159 }
2160
2161 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002162
2163 return printed;
2164}
2165
David Ahern896cbb52013-09-28 13:12:59 -06002166/* struct used to pass data to per-thread function */
2167struct summary_data {
2168 FILE *fp;
2169 struct trace *trace;
2170 size_t printed;
2171};
2172
2173static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2174{
2175 struct summary_data *data = priv;
2176 FILE *fp = data->fp;
2177 size_t printed = data->printed;
2178 struct trace *trace = data->trace;
2179 struct thread_trace *ttrace = thread->priv;
David Ahern896cbb52013-09-28 13:12:59 -06002180 double ratio;
2181
2182 if (ttrace == NULL)
2183 return 0;
2184
2185 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2186
Pekka Enberg15e65c62013-11-14 18:43:30 +02002187 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002188 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002189 printed += fprintf(fp, "%.1f%%", ratio);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002190 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002191 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002192
2193 data->printed += printed;
2194
2195 return 0;
2196}
2197
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002198static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2199{
David Ahern896cbb52013-09-28 13:12:59 -06002200 struct summary_data data = {
2201 .fp = fp,
2202 .trace = trace
2203 };
2204 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002205
David Ahern896cbb52013-09-28 13:12:59 -06002206 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002207
David Ahern896cbb52013-09-28 13:12:59 -06002208 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002209}
2210
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002211static int trace__set_duration(const struct option *opt, const char *str,
2212 int unset __maybe_unused)
2213{
2214 struct trace *trace = opt->value;
2215
2216 trace->duration_filter = atof(str);
2217 return 0;
2218}
2219
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002220static int trace__open_output(struct trace *trace, const char *filename)
2221{
2222 struct stat st;
2223
2224 if (!stat(filename, &st) && st.st_size) {
2225 char oldname[PATH_MAX];
2226
2227 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2228 unlink(oldname);
2229 rename(filename, oldname);
2230 }
2231
2232 trace->output = fopen(filename, "w");
2233
2234 return trace->output == NULL ? -errno : 0;
2235}
2236
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002237int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2238{
2239 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002240 "perf trace [<options>] [<command>]",
2241 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002242 "perf trace record [<options>] [<command>]",
2243 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002244 NULL
2245 };
2246 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002247 .audit = {
2248 .machine = audit_detect_machine(),
2249 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2250 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002251 .syscalls = {
2252 . max = -1,
2253 },
2254 .opts = {
2255 .target = {
2256 .uid = UINT_MAX,
2257 .uses_mmap = true,
2258 },
2259 .user_freq = UINT_MAX,
2260 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002261 .no_buffering = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002262 .mmap_pages = 1024,
2263 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002264 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002265 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002266 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002267 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002268 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002269 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002270 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2271 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002272 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002273 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
2274 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002275 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002276 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002277 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2278 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002279 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002280 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002281 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002282 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002283 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002284 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002285 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002286 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002287 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2288 "number of mmap data pages",
2289 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002290 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002291 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002292 OPT_CALLBACK(0, "duration", &trace, "float",
2293 "show only events with duration > N.M ms",
2294 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002295 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002296 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002297 OPT_BOOLEAN('T', "time", &trace.full_time,
2298 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002299 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2300 "Show only syscall summary with statistics"),
2301 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2302 "Show all syscalls and summary with statistics"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002303 OPT_END()
2304 };
2305 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002306 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002307
David Ahern5e2485b2013-09-28 13:13:01 -06002308 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
2309 return trace__record(argc-2, &argv[2]);
2310
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002311 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002312
David Ahernfd2eaba2013-11-12 09:31:15 -07002313 /* summary_only implies summary option, but don't overwrite summary if set */
2314 if (trace.summary_only)
2315 trace.summary = trace.summary_only;
2316
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002317 if (output_name != NULL) {
2318 err = trace__open_output(&trace, output_name);
2319 if (err < 0) {
2320 perror("failed to create output file");
2321 goto out;
2322 }
2323 }
2324
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002325 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002326 const char *s = ev_qualifier_str;
2327
2328 trace.not_ev_qualifier = *s == '!';
2329 if (trace.not_ev_qualifier)
2330 ++s;
2331 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002332 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002333 fputs("Not enough memory to parse event qualifier",
2334 trace.output);
2335 err = -ENOMEM;
2336 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002337 }
2338 }
2339
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002340 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002341 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002342 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002343 fprintf(trace.output, "%s", bf);
2344 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002345 }
2346
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002347 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002348 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002349 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002350 fprintf(trace.output, "%s", bf);
2351 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002352 }
2353
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002354 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002355 trace.opts.target.system_wide = true;
2356
David Ahern6810fc92013-08-28 22:29:52 -06002357 if (input_name)
2358 err = trace__replay(&trace);
2359 else
2360 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002361
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002362out_close:
2363 if (output_name != NULL)
2364 fclose(trace.output);
2365out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002366 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002367}