blob: 329b7832b5dac7d46ace24cc597e7539cbfddd8d [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"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030014
15#include <libaudit.h>
16#include <stdlib.h>
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -030017#include <sys/eventfd.h>
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030018#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030019#include <linux/futex.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030020
Ingo Molnar456857b2013-09-12 15:29:00 +020021/* For older distros: */
22#ifndef MAP_STACK
23# define MAP_STACK 0x20000
24#endif
25
26#ifndef MADV_HWPOISON
27# define MADV_HWPOISON 100
28#endif
29
30#ifndef MADV_MERGEABLE
31# define MADV_MERGEABLE 12
32#endif
33
34#ifndef MADV_UNMERGEABLE
35# define MADV_UNMERGEABLE 13
36#endif
37
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -030038struct tp_field {
39 int offset;
40 union {
41 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
42 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
43 };
44};
45
46#define TP_UINT_FIELD(bits) \
47static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
48{ \
49 return *(u##bits *)(sample->raw_data + field->offset); \
50}
51
52TP_UINT_FIELD(8);
53TP_UINT_FIELD(16);
54TP_UINT_FIELD(32);
55TP_UINT_FIELD(64);
56
57#define TP_UINT_FIELD__SWAPPED(bits) \
58static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
59{ \
60 u##bits value = *(u##bits *)(sample->raw_data + field->offset); \
61 return bswap_##bits(value);\
62}
63
64TP_UINT_FIELD__SWAPPED(16);
65TP_UINT_FIELD__SWAPPED(32);
66TP_UINT_FIELD__SWAPPED(64);
67
68static int tp_field__init_uint(struct tp_field *field,
69 struct format_field *format_field,
70 bool needs_swap)
71{
72 field->offset = format_field->offset;
73
74 switch (format_field->size) {
75 case 1:
76 field->integer = tp_field__u8;
77 break;
78 case 2:
79 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
80 break;
81 case 4:
82 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
83 break;
84 case 8:
85 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
86 break;
87 default:
88 return -1;
89 }
90
91 return 0;
92}
93
94static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
95{
96 return sample->raw_data + field->offset;
97}
98
99static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
100{
101 field->offset = format_field->offset;
102 field->pointer = tp_field__ptr;
103 return 0;
104}
105
106struct syscall_tp {
107 struct tp_field id;
108 union {
109 struct tp_field args, ret;
110 };
111};
112
113static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
114 struct tp_field *field,
115 const char *name)
116{
117 struct format_field *format_field = perf_evsel__field(evsel, name);
118
119 if (format_field == NULL)
120 return -1;
121
122 return tp_field__init_uint(field, format_field, evsel->needs_swap);
123}
124
125#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
126 ({ struct syscall_tp *sc = evsel->priv;\
127 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
128
129static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
130 struct tp_field *field,
131 const char *name)
132{
133 struct format_field *format_field = perf_evsel__field(evsel, name);
134
135 if (format_field == NULL)
136 return -1;
137
138 return tp_field__init_ptr(field, format_field);
139}
140
141#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
142 ({ struct syscall_tp *sc = evsel->priv;\
143 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
144
145static void perf_evsel__delete_priv(struct perf_evsel *evsel)
146{
147 free(evsel->priv);
148 evsel->priv = NULL;
149 perf_evsel__delete(evsel);
150}
151
152static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction,
153 void *handler, int idx)
154{
155 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction, idx);
156
157 if (evsel) {
158 evsel->priv = malloc(sizeof(struct syscall_tp));
159
160 if (evsel->priv == NULL)
161 goto out_delete;
162
163 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
164 goto out_delete;
165
166 evsel->handler = handler;
167 }
168
169 return evsel;
170
171out_delete:
172 perf_evsel__delete_priv(evsel);
173 return NULL;
174}
175
176#define perf_evsel__sc_tp_uint(evsel, name, sample) \
177 ({ struct syscall_tp *fields = evsel->priv; \
178 fields->name.integer(&fields->name, sample); })
179
180#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
181 ({ struct syscall_tp *fields = evsel->priv; \
182 fields->name.pointer(&fields->name, sample); })
183
184static int perf_evlist__add_syscall_newtp(struct perf_evlist *evlist,
185 void *sys_enter_handler,
186 void *sys_exit_handler)
187{
188 int ret = -1;
189 int idx = evlist->nr_entries;
190 struct perf_evsel *sys_enter, *sys_exit;
191
192 sys_enter = perf_evsel__syscall_newtp("sys_enter", sys_enter_handler, idx++);
193 if (sys_enter == NULL)
194 goto out;
195
196 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
197 goto out_delete_sys_enter;
198
199 sys_exit = perf_evsel__syscall_newtp("sys_exit", sys_exit_handler, idx++);
200 if (sys_exit == NULL)
201 goto out_delete_sys_enter;
202
203 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
204 goto out_delete_sys_exit;
205
206 perf_evlist__add(evlist, sys_enter);
207 perf_evlist__add(evlist, sys_exit);
208
209 ret = 0;
210out:
211 return ret;
212
213out_delete_sys_exit:
214 perf_evsel__delete_priv(sys_exit);
215out_delete_sys_enter:
216 perf_evsel__delete_priv(sys_enter);
217 goto out;
218}
219
220
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300221struct syscall_arg {
222 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300223 struct thread *thread;
224 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300225 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300226 u8 idx;
227 u8 mask;
228};
229
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300230struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300231 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300232 int nr_entries;
233 const char **entries;
234};
235
236#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
237 .nr_entries = ARRAY_SIZE(array), \
238 .entries = array, \
239}
240
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300241#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
242 .offset = off, \
243 .nr_entries = ARRAY_SIZE(array), \
244 .entries = array, \
245}
246
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300247static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
248 const char *intfmt,
249 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300250{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300251 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300252 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300253
254 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300255 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300256
257 return scnprintf(bf, size, "%s", sa->entries[idx]);
258}
259
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300260static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
261 struct syscall_arg *arg)
262{
263 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
264}
265
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300266#define SCA_STRARRAY syscall_arg__scnprintf_strarray
267
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300268static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
269 struct syscall_arg *arg)
270{
271 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
272}
273
274#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
275
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300276static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
277 struct syscall_arg *arg);
278
279#define SCA_FD syscall_arg__scnprintf_fd
280
281static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
282 struct syscall_arg *arg)
283{
284 int fd = arg->val;
285
286 if (fd == AT_FDCWD)
287 return scnprintf(bf, size, "CWD");
288
289 return syscall_arg__scnprintf_fd(bf, size, arg);
290}
291
292#define SCA_FDAT syscall_arg__scnprintf_fd_at
293
294static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
295 struct syscall_arg *arg);
296
297#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
298
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300299static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300300 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300301{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300302 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300303}
304
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300305#define SCA_HEX syscall_arg__scnprintf_hex
306
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300307static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300308 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300309{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300310 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300311
312 if (prot == PROT_NONE)
313 return scnprintf(bf, size, "NONE");
314#define P_MMAP_PROT(n) \
315 if (prot & PROT_##n) { \
316 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
317 prot &= ~PROT_##n; \
318 }
319
320 P_MMAP_PROT(EXEC);
321 P_MMAP_PROT(READ);
322 P_MMAP_PROT(WRITE);
323#ifdef PROT_SEM
324 P_MMAP_PROT(SEM);
325#endif
326 P_MMAP_PROT(GROWSDOWN);
327 P_MMAP_PROT(GROWSUP);
328#undef P_MMAP_PROT
329
330 if (prot)
331 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
332
333 return printed;
334}
335
336#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
337
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300338static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300339 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300340{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300341 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300342
343#define P_MMAP_FLAG(n) \
344 if (flags & MAP_##n) { \
345 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
346 flags &= ~MAP_##n; \
347 }
348
349 P_MMAP_FLAG(SHARED);
350 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400351#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300352 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400353#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300354 P_MMAP_FLAG(ANONYMOUS);
355 P_MMAP_FLAG(DENYWRITE);
356 P_MMAP_FLAG(EXECUTABLE);
357 P_MMAP_FLAG(FILE);
358 P_MMAP_FLAG(FIXED);
359 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600360#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300361 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600362#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300363 P_MMAP_FLAG(LOCKED);
364 P_MMAP_FLAG(NONBLOCK);
365 P_MMAP_FLAG(NORESERVE);
366 P_MMAP_FLAG(POPULATE);
367 P_MMAP_FLAG(STACK);
368#ifdef MAP_UNINITIALIZED
369 P_MMAP_FLAG(UNINITIALIZED);
370#endif
371#undef P_MMAP_FLAG
372
373 if (flags)
374 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
375
376 return printed;
377}
378
379#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
380
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300381static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300382 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300383{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300384 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300385
386 switch (behavior) {
387#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
388 P_MADV_BHV(NORMAL);
389 P_MADV_BHV(RANDOM);
390 P_MADV_BHV(SEQUENTIAL);
391 P_MADV_BHV(WILLNEED);
392 P_MADV_BHV(DONTNEED);
393 P_MADV_BHV(REMOVE);
394 P_MADV_BHV(DONTFORK);
395 P_MADV_BHV(DOFORK);
396 P_MADV_BHV(HWPOISON);
397#ifdef MADV_SOFT_OFFLINE
398 P_MADV_BHV(SOFT_OFFLINE);
399#endif
400 P_MADV_BHV(MERGEABLE);
401 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600402#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300403 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600404#endif
405#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300406 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600407#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300408#ifdef MADV_DONTDUMP
409 P_MADV_BHV(DONTDUMP);
410#endif
411#ifdef MADV_DODUMP
412 P_MADV_BHV(DODUMP);
413#endif
414#undef P_MADV_PHV
415 default: break;
416 }
417
418 return scnprintf(bf, size, "%#x", behavior);
419}
420
421#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
422
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300423static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
424 struct syscall_arg *arg)
425{
426 int printed = 0, op = arg->val;
427
428 if (op == 0)
429 return scnprintf(bf, size, "NONE");
430#define P_CMD(cmd) \
431 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
432 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
433 op &= ~LOCK_##cmd; \
434 }
435
436 P_CMD(SH);
437 P_CMD(EX);
438 P_CMD(NB);
439 P_CMD(UN);
440 P_CMD(MAND);
441 P_CMD(RW);
442 P_CMD(READ);
443 P_CMD(WRITE);
444#undef P_OP
445
446 if (op)
447 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
448
449 return printed;
450}
451
452#define SCA_FLOCK syscall_arg__scnprintf_flock
453
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300454static 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 -0300455{
456 enum syscall_futex_args {
457 SCF_UADDR = (1 << 0),
458 SCF_OP = (1 << 1),
459 SCF_VAL = (1 << 2),
460 SCF_TIMEOUT = (1 << 3),
461 SCF_UADDR2 = (1 << 4),
462 SCF_VAL3 = (1 << 5),
463 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300464 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300465 int cmd = op & FUTEX_CMD_MASK;
466 size_t printed = 0;
467
468 switch (cmd) {
469#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300470 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
471 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
472 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
473 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
474 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
475 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300476 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300477 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
478 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
479 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
480 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
481 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300482 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
483 default: printed = scnprintf(bf, size, "%#x", cmd); break;
484 }
485
486 if (op & FUTEX_PRIVATE_FLAG)
487 printed += scnprintf(bf + printed, size - printed, "|PRIV");
488
489 if (op & FUTEX_CLOCK_REALTIME)
490 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
491
492 return printed;
493}
494
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300495#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
496
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300497static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
498static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300499
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300500static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
501static DEFINE_STRARRAY(itimers);
502
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300503static const char *whences[] = { "SET", "CUR", "END",
504#ifdef SEEK_DATA
505"DATA",
506#endif
507#ifdef SEEK_HOLE
508"HOLE",
509#endif
510};
511static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300512
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300513static const char *fcntl_cmds[] = {
514 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
515 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
516 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
517 "F_GETOWNER_UIDS",
518};
519static DEFINE_STRARRAY(fcntl_cmds);
520
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300521static const char *rlimit_resources[] = {
522 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
523 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
524 "RTTIME",
525};
526static DEFINE_STRARRAY(rlimit_resources);
527
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300528static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
529static DEFINE_STRARRAY(sighow);
530
David Ahern4f8c1b72013-09-22 19:45:00 -0600531static const char *clockid[] = {
532 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
533 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
534};
535static DEFINE_STRARRAY(clockid);
536
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300537static const char *socket_families[] = {
538 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
539 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
540 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
541 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
542 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
543 "ALG", "NFC", "VSOCK",
544};
545static DEFINE_STRARRAY(socket_families);
546
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300547#ifndef SOCK_TYPE_MASK
548#define SOCK_TYPE_MASK 0xf
549#endif
550
551static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
552 struct syscall_arg *arg)
553{
554 size_t printed;
555 int type = arg->val,
556 flags = type & ~SOCK_TYPE_MASK;
557
558 type &= SOCK_TYPE_MASK;
559 /*
560 * Can't use a strarray, MIPS may override for ABI reasons.
561 */
562 switch (type) {
563#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
564 P_SK_TYPE(STREAM);
565 P_SK_TYPE(DGRAM);
566 P_SK_TYPE(RAW);
567 P_SK_TYPE(RDM);
568 P_SK_TYPE(SEQPACKET);
569 P_SK_TYPE(DCCP);
570 P_SK_TYPE(PACKET);
571#undef P_SK_TYPE
572 default:
573 printed = scnprintf(bf, size, "%#x", type);
574 }
575
576#define P_SK_FLAG(n) \
577 if (flags & SOCK_##n) { \
578 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
579 flags &= ~SOCK_##n; \
580 }
581
582 P_SK_FLAG(CLOEXEC);
583 P_SK_FLAG(NONBLOCK);
584#undef P_SK_FLAG
585
586 if (flags)
587 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
588
589 return printed;
590}
591
592#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
593
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300594#ifndef MSG_PROBE
595#define MSG_PROBE 0x10
596#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600597#ifndef MSG_WAITFORONE
598#define MSG_WAITFORONE 0x10000
599#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300600#ifndef MSG_SENDPAGE_NOTLAST
601#define MSG_SENDPAGE_NOTLAST 0x20000
602#endif
603#ifndef MSG_FASTOPEN
604#define MSG_FASTOPEN 0x20000000
605#endif
606
607static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
608 struct syscall_arg *arg)
609{
610 int printed = 0, flags = arg->val;
611
612 if (flags == 0)
613 return scnprintf(bf, size, "NONE");
614#define P_MSG_FLAG(n) \
615 if (flags & MSG_##n) { \
616 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
617 flags &= ~MSG_##n; \
618 }
619
620 P_MSG_FLAG(OOB);
621 P_MSG_FLAG(PEEK);
622 P_MSG_FLAG(DONTROUTE);
623 P_MSG_FLAG(TRYHARD);
624 P_MSG_FLAG(CTRUNC);
625 P_MSG_FLAG(PROBE);
626 P_MSG_FLAG(TRUNC);
627 P_MSG_FLAG(DONTWAIT);
628 P_MSG_FLAG(EOR);
629 P_MSG_FLAG(WAITALL);
630 P_MSG_FLAG(FIN);
631 P_MSG_FLAG(SYN);
632 P_MSG_FLAG(CONFIRM);
633 P_MSG_FLAG(RST);
634 P_MSG_FLAG(ERRQUEUE);
635 P_MSG_FLAG(NOSIGNAL);
636 P_MSG_FLAG(MORE);
637 P_MSG_FLAG(WAITFORONE);
638 P_MSG_FLAG(SENDPAGE_NOTLAST);
639 P_MSG_FLAG(FASTOPEN);
640 P_MSG_FLAG(CMSG_CLOEXEC);
641#undef P_MSG_FLAG
642
643 if (flags)
644 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
645
646 return printed;
647}
648
649#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
650
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300651static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
652 struct syscall_arg *arg)
653{
654 size_t printed = 0;
655 int mode = arg->val;
656
657 if (mode == F_OK) /* 0 */
658 return scnprintf(bf, size, "F");
659#define P_MODE(n) \
660 if (mode & n##_OK) { \
661 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
662 mode &= ~n##_OK; \
663 }
664
665 P_MODE(R);
666 P_MODE(W);
667 P_MODE(X);
668#undef P_MODE
669
670 if (mode)
671 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
672
673 return printed;
674}
675
676#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
677
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300678static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300679 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300680{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300681 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300682
683 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300684 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300685
686 if (flags == 0)
687 return scnprintf(bf, size, "RDONLY");
688#define P_FLAG(n) \
689 if (flags & O_##n) { \
690 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
691 flags &= ~O_##n; \
692 }
693
694 P_FLAG(APPEND);
695 P_FLAG(ASYNC);
696 P_FLAG(CLOEXEC);
697 P_FLAG(CREAT);
698 P_FLAG(DIRECT);
699 P_FLAG(DIRECTORY);
700 P_FLAG(EXCL);
701 P_FLAG(LARGEFILE);
702 P_FLAG(NOATIME);
703 P_FLAG(NOCTTY);
704#ifdef O_NONBLOCK
705 P_FLAG(NONBLOCK);
706#elif O_NDELAY
707 P_FLAG(NDELAY);
708#endif
709#ifdef O_PATH
710 P_FLAG(PATH);
711#endif
712 P_FLAG(RDWR);
713#ifdef O_DSYNC
714 if ((flags & O_SYNC) == O_SYNC)
715 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
716 else {
717 P_FLAG(DSYNC);
718 }
719#else
720 P_FLAG(SYNC);
721#endif
722 P_FLAG(TRUNC);
723 P_FLAG(WRONLY);
724#undef P_FLAG
725
726 if (flags)
727 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
728
729 return printed;
730}
731
732#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
733
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300734static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
735 struct syscall_arg *arg)
736{
737 int printed = 0, flags = arg->val;
738
739 if (flags == 0)
740 return scnprintf(bf, size, "NONE");
741#define P_FLAG(n) \
742 if (flags & EFD_##n) { \
743 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
744 flags &= ~EFD_##n; \
745 }
746
747 P_FLAG(SEMAPHORE);
748 P_FLAG(CLOEXEC);
749 P_FLAG(NONBLOCK);
750#undef P_FLAG
751
752 if (flags)
753 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
754
755 return printed;
756}
757
758#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
759
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300760static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
761 struct syscall_arg *arg)
762{
763 int printed = 0, flags = arg->val;
764
765#define P_FLAG(n) \
766 if (flags & O_##n) { \
767 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
768 flags &= ~O_##n; \
769 }
770
771 P_FLAG(CLOEXEC);
772 P_FLAG(NONBLOCK);
773#undef P_FLAG
774
775 if (flags)
776 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
777
778 return printed;
779}
780
781#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
782
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300783static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
784{
785 int sig = arg->val;
786
787 switch (sig) {
788#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
789 P_SIGNUM(HUP);
790 P_SIGNUM(INT);
791 P_SIGNUM(QUIT);
792 P_SIGNUM(ILL);
793 P_SIGNUM(TRAP);
794 P_SIGNUM(ABRT);
795 P_SIGNUM(BUS);
796 P_SIGNUM(FPE);
797 P_SIGNUM(KILL);
798 P_SIGNUM(USR1);
799 P_SIGNUM(SEGV);
800 P_SIGNUM(USR2);
801 P_SIGNUM(PIPE);
802 P_SIGNUM(ALRM);
803 P_SIGNUM(TERM);
804 P_SIGNUM(STKFLT);
805 P_SIGNUM(CHLD);
806 P_SIGNUM(CONT);
807 P_SIGNUM(STOP);
808 P_SIGNUM(TSTP);
809 P_SIGNUM(TTIN);
810 P_SIGNUM(TTOU);
811 P_SIGNUM(URG);
812 P_SIGNUM(XCPU);
813 P_SIGNUM(XFSZ);
814 P_SIGNUM(VTALRM);
815 P_SIGNUM(PROF);
816 P_SIGNUM(WINCH);
817 P_SIGNUM(IO);
818 P_SIGNUM(PWR);
819 P_SIGNUM(SYS);
820 default: break;
821 }
822
823 return scnprintf(bf, size, "%#x", sig);
824}
825
826#define SCA_SIGNUM syscall_arg__scnprintf_signum
827
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300828#define TCGETS 0x5401
829
830static const char *tioctls[] = {
831 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
832 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
833 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
834 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
835 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
836 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
837 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
838 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
839 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
840 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
841 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
842 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
843 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
844 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
845 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
846};
847
848static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
849
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300850#define STRARRAY(arg, name, array) \
851 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
852 .arg_parm = { [arg] = &strarray__##array, }
853
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300854static struct syscall_fmt {
855 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300856 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300857 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300858 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300859 bool errmsg;
860 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300861 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300862} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300863 { .name = "access", .errmsg = true,
864 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300865 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300866 { .name = "brk", .hexret = true,
867 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600868 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300869 { .name = "close", .errmsg = true,
870 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300871 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300872 { .name = "dup", .errmsg = true,
873 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
874 { .name = "dup2", .errmsg = true,
875 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
876 { .name = "dup3", .errmsg = true,
877 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300878 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300879 { .name = "eventfd2", .errmsg = true,
880 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300881 { .name = "faccessat", .errmsg = true,
882 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
883 { .name = "fadvise64", .errmsg = true,
884 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
885 { .name = "fallocate", .errmsg = true,
886 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
887 { .name = "fchdir", .errmsg = true,
888 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
889 { .name = "fchmod", .errmsg = true,
890 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
891 { .name = "fchmodat", .errmsg = true,
892 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
893 { .name = "fchown", .errmsg = true,
894 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
895 { .name = "fchownat", .errmsg = true,
896 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
897 { .name = "fcntl", .errmsg = true,
898 .arg_scnprintf = { [0] = SCA_FD, /* fd */
899 [1] = SCA_STRARRAY, /* cmd */ },
900 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
901 { .name = "fdatasync", .errmsg = true,
902 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300903 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300904 .arg_scnprintf = { [0] = SCA_FD, /* fd */
905 [1] = SCA_FLOCK, /* cmd */ }, },
906 { .name = "fsetxattr", .errmsg = true,
907 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
908 { .name = "fstat", .errmsg = true, .alias = "newfstat",
909 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
910 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
911 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
912 { .name = "fstatfs", .errmsg = true,
913 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
914 { .name = "fsync", .errmsg = true,
915 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
916 { .name = "ftruncate", .errmsg = true,
917 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300918 { .name = "futex", .errmsg = true,
919 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300920 { .name = "futimesat", .errmsg = true,
921 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
922 { .name = "getdents", .errmsg = true,
923 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
924 { .name = "getdents64", .errmsg = true,
925 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300926 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
927 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300928 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300929 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300930 [1] = SCA_STRHEXARRAY, /* cmd */
931 [2] = SCA_HEX, /* arg */ },
932 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300933 { .name = "kill", .errmsg = true,
934 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300935 { .name = "linkat", .errmsg = true,
936 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
937 { .name = "lseek", .errmsg = true,
938 .arg_scnprintf = { [0] = SCA_FD, /* fd */
939 [2] = SCA_STRARRAY, /* whence */ },
940 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300941 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300942 { .name = "madvise", .errmsg = true,
943 .arg_scnprintf = { [0] = SCA_HEX, /* start */
944 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300945 { .name = "mkdirat", .errmsg = true,
946 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
947 { .name = "mknodat", .errmsg = true,
948 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300949 { .name = "mlock", .errmsg = true,
950 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
951 { .name = "mlockall", .errmsg = true,
952 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300953 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300954 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300955 [2] = SCA_MMAP_PROT, /* prot */
956 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300957 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300958 .arg_scnprintf = { [0] = SCA_HEX, /* start */
959 [2] = SCA_MMAP_PROT, /* prot */ }, },
960 { .name = "mremap", .hexret = true,
961 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
962 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300963 { .name = "munlock", .errmsg = true,
964 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300965 { .name = "munmap", .errmsg = true,
966 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300967 { .name = "name_to_handle_at", .errmsg = true,
968 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
969 { .name = "newfstatat", .errmsg = true,
970 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300971 { .name = "open", .errmsg = true,
972 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300973 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300974 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
975 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300976 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300977 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
978 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300979 { .name = "pipe2", .errmsg = true,
980 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300981 { .name = "poll", .errmsg = true, .timeout = true, },
982 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300983 { .name = "pread", .errmsg = true, .alias = "pread64",
984 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
985 { .name = "preadv", .errmsg = true, .alias = "pread",
986 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300987 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300988 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
989 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
990 { .name = "pwritev", .errmsg = true,
991 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
992 { .name = "read", .errmsg = true,
993 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
994 { .name = "readlinkat", .errmsg = true,
995 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
996 { .name = "readv", .errmsg = true,
997 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300998 { .name = "recvfrom", .errmsg = true,
999 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1000 { .name = "recvmmsg", .errmsg = true,
1001 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1002 { .name = "recvmsg", .errmsg = true,
1003 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001004 { .name = "renameat", .errmsg = true,
1005 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001006 { .name = "rt_sigaction", .errmsg = true,
1007 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001008 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001009 { .name = "rt_sigqueueinfo", .errmsg = true,
1010 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1011 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1012 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001013 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001014 { .name = "sendmmsg", .errmsg = true,
1015 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1016 { .name = "sendmsg", .errmsg = true,
1017 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
1018 { .name = "sendto", .errmsg = true,
1019 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001020 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1021 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001022 { .name = "shutdown", .errmsg = true,
1023 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001024 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001025 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1026 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001027 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001028 { .name = "socketpair", .errmsg = true,
1029 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1030 [1] = SCA_SK_TYPE, /* type */ },
1031 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001032 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001033 { .name = "symlinkat", .errmsg = true,
1034 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001035 { .name = "tgkill", .errmsg = true,
1036 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1037 { .name = "tkill", .errmsg = true,
1038 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001039 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001040 { .name = "unlinkat", .errmsg = true,
1041 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1042 { .name = "utimensat", .errmsg = true,
1043 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
1044 { .name = "write", .errmsg = true,
1045 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1046 { .name = "writev", .errmsg = true,
1047 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001048};
1049
1050static int syscall_fmt__cmp(const void *name, const void *fmtp)
1051{
1052 const struct syscall_fmt *fmt = fmtp;
1053 return strcmp(name, fmt->name);
1054}
1055
1056static struct syscall_fmt *syscall_fmt__find(const char *name)
1057{
1058 const int nmemb = ARRAY_SIZE(syscall_fmts);
1059 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1060}
1061
1062struct syscall {
1063 struct event_format *tp_format;
1064 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001065 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001066 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001067 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001068 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001069};
1070
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001071static size_t fprintf_duration(unsigned long t, FILE *fp)
1072{
1073 double duration = (double)t / NSEC_PER_MSEC;
1074 size_t printed = fprintf(fp, "(");
1075
1076 if (duration >= 1.0)
1077 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1078 else if (duration >= 0.01)
1079 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1080 else
1081 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001082 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001083}
1084
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001085struct thread_trace {
1086 u64 entry_time;
1087 u64 exit_time;
1088 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001089 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001090 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001091 double runtime_ms;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001092 struct {
1093 int max;
1094 char **table;
1095 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001096
1097 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001098};
1099
1100static struct thread_trace *thread_trace__new(void)
1101{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001102 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1103
1104 if (ttrace)
1105 ttrace->paths.max = -1;
1106
David Ahernbf2575c2013-10-08 21:26:53 -06001107 ttrace->syscall_stats = intlist__new(NULL);
1108
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001109 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001110}
1111
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001112static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001113{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001114 struct thread_trace *ttrace;
1115
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001116 if (thread == NULL)
1117 goto fail;
1118
1119 if (thread->priv == NULL)
1120 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001121
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001122 if (thread->priv == NULL)
1123 goto fail;
1124
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001125 ttrace = thread->priv;
1126 ++ttrace->nr_events;
1127
1128 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001129fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001130 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001131 "WARNING: not enough memory, dropping samples!\n");
1132 return NULL;
1133}
1134
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001135struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001136 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001137 struct {
1138 int machine;
1139 int open_id;
1140 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001141 struct {
1142 int max;
1143 struct syscall *table;
1144 } syscalls;
1145 struct perf_record_opts opts;
David Ahern8fb598e2013-09-28 13:13:00 -06001146 struct machine *host;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001147 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -06001148 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001149 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001150 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001151 struct strlist *ev_qualifier;
1152 bool not_ev_qualifier;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001153 bool live;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001154 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -06001155 struct intlist *tid_list;
1156 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001157 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001158 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001159 bool summary;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001160 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001161 bool show_tool_stats;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001162 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001163 double runtime_ms;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001164 struct {
1165 u64 vfs_getname, proc_getname;
1166 } stats;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001167};
1168
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001169static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001170{
1171 struct thread_trace *ttrace = thread->priv;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001172
1173 if (fd > ttrace->paths.max) {
1174 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1175
1176 if (npath == NULL)
1177 return -1;
1178
1179 if (ttrace->paths.max != -1) {
1180 memset(npath + ttrace->paths.max + 1, 0,
1181 (fd - ttrace->paths.max) * sizeof(char *));
1182 } else {
1183 memset(npath, 0, (fd + 1) * sizeof(char *));
1184 }
1185
1186 ttrace->paths.table = npath;
1187 ttrace->paths.max = fd;
1188 }
1189
1190 ttrace->paths.table[fd] = strdup(pathname);
1191
1192 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1193}
1194
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001195static int thread__read_fd_path(struct thread *thread, int fd)
1196{
1197 char linkname[PATH_MAX], pathname[PATH_MAX];
1198 struct stat st;
1199 int ret;
1200
1201 if (thread->pid_ == thread->tid) {
1202 scnprintf(linkname, sizeof(linkname),
1203 "/proc/%d/fd/%d", thread->pid_, fd);
1204 } else {
1205 scnprintf(linkname, sizeof(linkname),
1206 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1207 }
1208
1209 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1210 return -1;
1211
1212 ret = readlink(linkname, pathname, sizeof(pathname));
1213
1214 if (ret < 0 || ret > st.st_size)
1215 return -1;
1216
1217 pathname[ret] = '\0';
1218 return trace__set_fd_pathname(thread, fd, pathname);
1219}
1220
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001221static const char *thread__fd_path(struct thread *thread, int fd,
1222 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001223{
1224 struct thread_trace *ttrace = thread->priv;
1225
1226 if (ttrace == NULL)
1227 return NULL;
1228
1229 if (fd < 0)
1230 return NULL;
1231
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001232 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL))
1233 if (!trace->live)
1234 return NULL;
1235 ++trace->stats.proc_getname;
1236 if (thread__read_fd_path(thread, fd)) {
1237 return NULL;
1238 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001239
1240 return ttrace->paths.table[fd];
1241}
1242
1243static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1244 struct syscall_arg *arg)
1245{
1246 int fd = arg->val;
1247 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001248 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001249
1250 if (path)
1251 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1252
1253 return printed;
1254}
1255
1256static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1257 struct syscall_arg *arg)
1258{
1259 int fd = arg->val;
1260 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1261 struct thread_trace *ttrace = arg->thread->priv;
1262
1263 if (ttrace && fd >= 0 && fd <= ttrace->paths.max) {
1264 free(ttrace->paths.table[fd]);
1265 ttrace->paths.table[fd] = NULL;
1266 }
1267
1268 return printed;
1269}
1270
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001271static bool trace__filter_duration(struct trace *trace, double t)
1272{
1273 return t < (trace->duration_filter * NSEC_PER_MSEC);
1274}
1275
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001276static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1277{
1278 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1279
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001280 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001281}
1282
Namhyung Kimf15eb532012-10-05 14:02:16 +09001283static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001284static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001285
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001286static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001287{
1288 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001289 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001290}
1291
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001292static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001293 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001294{
1295 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001296 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001297
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001298 if (trace->multiple_threads) {
1299 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001300 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001301 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001302 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001303
1304 return printed;
1305}
1306
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001307static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001308 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001309{
1310 int ret = 0;
1311
1312 switch (event->header.type) {
1313 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001314 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001315 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001316 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001317 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001318 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001319 break;
1320 }
1321
1322 return ret;
1323}
1324
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001325static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001326 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001327 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001328 struct machine *machine)
1329{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001330 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001331 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001332}
1333
1334static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1335{
1336 int err = symbol__init();
1337
1338 if (err)
1339 return err;
1340
David Ahern8fb598e2013-09-28 13:13:00 -06001341 trace->host = machine__new_host();
1342 if (trace->host == NULL)
1343 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001344
1345 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001346 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001347 trace__tool_process,
David Ahern8fb598e2013-09-28 13:13:00 -06001348 trace->host);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001349 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001350 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
David Ahern8fb598e2013-09-28 13:13:00 -06001351 trace->host);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001352 }
1353
1354 if (err)
1355 symbol__exit();
1356
1357 return err;
1358}
1359
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001360static int syscall__set_arg_fmts(struct syscall *sc)
1361{
1362 struct format_field *field;
1363 int idx = 0;
1364
1365 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1366 if (sc->arg_scnprintf == NULL)
1367 return -1;
1368
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001369 if (sc->fmt)
1370 sc->arg_parm = sc->fmt->arg_parm;
1371
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001372 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001373 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1374 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1375 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001376 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1377 ++idx;
1378 }
1379
1380 return 0;
1381}
1382
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001383static int trace__read_syscall_info(struct trace *trace, int id)
1384{
1385 char tp_name[128];
1386 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001387 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001388
1389 if (name == NULL)
1390 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001391
1392 if (id > trace->syscalls.max) {
1393 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1394
1395 if (nsyscalls == NULL)
1396 return -1;
1397
1398 if (trace->syscalls.max != -1) {
1399 memset(nsyscalls + trace->syscalls.max + 1, 0,
1400 (id - trace->syscalls.max) * sizeof(*sc));
1401 } else {
1402 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1403 }
1404
1405 trace->syscalls.table = nsyscalls;
1406 trace->syscalls.max = id;
1407 }
1408
1409 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001410 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001411
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001412 if (trace->ev_qualifier) {
1413 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1414
1415 if (!(in ^ trace->not_ev_qualifier)) {
1416 sc->filtered = true;
1417 /*
1418 * No need to do read tracepoint information since this will be
1419 * filtered out.
1420 */
1421 return 0;
1422 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001423 }
1424
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001425 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001426
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001427 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
1428 sc->tp_format = event_format__new("syscalls", tp_name);
1429
1430 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1431 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
1432 sc->tp_format = event_format__new("syscalls", tp_name);
1433 }
1434
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001435 if (sc->tp_format == NULL)
1436 return -1;
1437
1438 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001439}
1440
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001441static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001442 unsigned long *args, struct trace *trace,
1443 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001444{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001445 size_t printed = 0;
1446
1447 if (sc->tp_format != NULL) {
1448 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001449 u8 bit = 1;
1450 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001451 .idx = 0,
1452 .mask = 0,
1453 .trace = trace,
1454 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001455 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001456
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001457 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001458 field = field->next, ++arg.idx, bit <<= 1) {
1459 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001460 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001461 /*
1462 * Suppress this argument if its value is zero and
1463 * and we don't have a string associated in an
1464 * strarray for it.
1465 */
1466 if (args[arg.idx] == 0 &&
1467 !(sc->arg_scnprintf &&
1468 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1469 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001470 continue;
1471
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001472 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001473 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001474 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1475 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001476 if (sc->arg_parm)
1477 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001478 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1479 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001480 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001481 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001482 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001483 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001484 }
1485 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001486 int i = 0;
1487
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001488 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001489 printed += scnprintf(bf + printed, size - printed,
1490 "%sarg%d: %ld",
1491 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001492 ++i;
1493 }
1494 }
1495
1496 return printed;
1497}
1498
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001499typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1500 struct perf_sample *sample);
1501
1502static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001503 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001504{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001505
1506 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001507
1508 /*
1509 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1510 * before that, leaving at a higher verbosity level till that is
1511 * explained. Reproduced with plain ftrace with:
1512 *
1513 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1514 * grep "NR -1 " /t/trace_pipe
1515 *
1516 * After generating some load on the machine.
1517 */
1518 if (verbose > 1) {
1519 static u64 n;
1520 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1521 id, perf_evsel__name(evsel), ++n);
1522 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001523 return NULL;
1524 }
1525
1526 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1527 trace__read_syscall_info(trace, id))
1528 goto out_cant_read;
1529
1530 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1531 goto out_cant_read;
1532
1533 return &trace->syscalls.table[id];
1534
1535out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001536 if (verbose) {
1537 fprintf(trace->output, "Problems reading syscall %d", id);
1538 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1539 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1540 fputs(" information\n", trace->output);
1541 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001542 return NULL;
1543}
1544
David Ahernbf2575c2013-10-08 21:26:53 -06001545static void thread__update_stats(struct thread_trace *ttrace,
1546 int id, struct perf_sample *sample)
1547{
1548 struct int_node *inode;
1549 struct stats *stats;
1550 u64 duration = 0;
1551
1552 inode = intlist__findnew(ttrace->syscall_stats, id);
1553 if (inode == NULL)
1554 return;
1555
1556 stats = inode->priv;
1557 if (stats == NULL) {
1558 stats = malloc(sizeof(struct stats));
1559 if (stats == NULL)
1560 return;
1561 init_stats(stats);
1562 inode->priv = stats;
1563 }
1564
1565 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1566 duration = sample->time - ttrace->entry_time;
1567
1568 update_stats(stats, duration);
1569}
1570
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001571static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1572 struct perf_sample *sample)
1573{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001574 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001575 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001576 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001577 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001578 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001579 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001580 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001581
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001582 if (sc == NULL)
1583 return -1;
1584
1585 if (sc->filtered)
1586 return 0;
1587
David Ahern8fb598e2013-09-28 13:13:00 -06001588 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001589 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001590 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001591 return -1;
1592
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001593 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001594 ttrace = thread->priv;
1595
1596 if (ttrace->entry_str == NULL) {
1597 ttrace->entry_str = malloc(1024);
1598 if (!ttrace->entry_str)
1599 return -1;
1600 }
1601
1602 ttrace->entry_time = sample->time;
1603 msg = ttrace->entry_str;
1604 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1605
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001606 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1607 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001608
1609 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001610 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001611 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1612 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001613 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001614 } else
1615 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001616
1617 return 0;
1618}
1619
1620static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1621 struct perf_sample *sample)
1622{
1623 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001624 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001625 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001626 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001627 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001628 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001629
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001630 if (sc == NULL)
1631 return -1;
1632
1633 if (sc->filtered)
1634 return 0;
1635
David Ahern8fb598e2013-09-28 13:13:00 -06001636 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001637 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001638 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001639 return -1;
1640
David Ahernbf2575c2013-10-08 21:26:53 -06001641 if (trace->summary)
1642 thread__update_stats(ttrace, id, sample);
1643
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001644 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001645
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001646 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1647 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1648 trace->last_vfs_getname = NULL;
1649 ++trace->stats.vfs_getname;
1650 }
1651
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001652 ttrace = thread->priv;
1653
1654 ttrace->exit_time = sample->time;
1655
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001656 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001657 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001658 if (trace__filter_duration(trace, duration))
1659 goto out;
1660 } else if (trace->duration_filter)
1661 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001662
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001663 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001664
1665 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001666 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001667 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001668 fprintf(trace->output, " ... [");
1669 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1670 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001671 }
1672
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001673 if (sc->fmt == NULL) {
1674signed_print:
1675 fprintf(trace->output, ") = %d", ret);
1676 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001677 char bf[256];
1678 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1679 *e = audit_errno_to_name(-ret);
1680
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001681 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001682 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001683 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001684 else if (sc->fmt->hexret)
1685 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001686 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001687 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001688
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001689 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001690out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001691 ttrace->entry_pending = false;
1692
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001693 return 0;
1694}
1695
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001696static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1697 struct perf_sample *sample)
1698{
1699 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1700 return 0;
1701}
1702
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001703static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1704 struct perf_sample *sample)
1705{
1706 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1707 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001708 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001709 sample->pid,
1710 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001711 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001712
1713 if (ttrace == NULL)
1714 goto out_dump;
1715
1716 ttrace->runtime_ms += runtime_ms;
1717 trace->runtime_ms += runtime_ms;
1718 return 0;
1719
1720out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001721 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001722 evsel->name,
1723 perf_evsel__strval(evsel, sample, "comm"),
1724 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1725 runtime,
1726 perf_evsel__intval(evsel, sample, "vruntime"));
1727 return 0;
1728}
1729
David Ahernbdc89662013-08-28 22:29:53 -06001730static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1731{
1732 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1733 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1734 return false;
1735
1736 if (trace->pid_list || trace->tid_list)
1737 return true;
1738
1739 return false;
1740}
1741
David Ahern6810fc92013-08-28 22:29:52 -06001742static int trace__process_sample(struct perf_tool *tool,
1743 union perf_event *event __maybe_unused,
1744 struct perf_sample *sample,
1745 struct perf_evsel *evsel,
1746 struct machine *machine __maybe_unused)
1747{
1748 struct trace *trace = container_of(tool, struct trace, tool);
1749 int err = 0;
1750
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001751 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001752
David Ahernbdc89662013-08-28 22:29:53 -06001753 if (skip_sample(trace, sample))
1754 return 0;
1755
David Ahern4bb09192013-09-04 12:37:43 -06001756 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001757 trace->base_time = sample->time;
1758
1759 if (handler)
1760 handler(trace, evsel, sample);
1761
1762 return err;
1763}
1764
1765static bool
1766perf_session__has_tp(struct perf_session *session, const char *name)
1767{
1768 struct perf_evsel *evsel;
1769
1770 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1771
1772 return evsel != NULL;
1773}
1774
David Ahernbdc89662013-08-28 22:29:53 -06001775static int parse_target_str(struct trace *trace)
1776{
1777 if (trace->opts.target.pid) {
1778 trace->pid_list = intlist__new(trace->opts.target.pid);
1779 if (trace->pid_list == NULL) {
1780 pr_err("Error parsing process id string\n");
1781 return -EINVAL;
1782 }
1783 }
1784
1785 if (trace->opts.target.tid) {
1786 trace->tid_list = intlist__new(trace->opts.target.tid);
1787 if (trace->tid_list == NULL) {
1788 pr_err("Error parsing thread id string\n");
1789 return -EINVAL;
1790 }
1791 }
1792
1793 return 0;
1794}
1795
David Ahern5e2485b2013-09-28 13:13:01 -06001796static int trace__record(int argc, const char **argv)
1797{
1798 unsigned int rec_argc, i, j;
1799 const char **rec_argv;
1800 const char * const record_args[] = {
1801 "record",
1802 "-R",
1803 "-m", "1024",
1804 "-c", "1",
1805 "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit",
1806 };
1807
1808 rec_argc = ARRAY_SIZE(record_args) + argc;
1809 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1810
1811 if (rec_argv == NULL)
1812 return -ENOMEM;
1813
1814 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1815 rec_argv[i] = record_args[i];
1816
1817 for (j = 0; j < (unsigned int)argc; j++, i++)
1818 rec_argv[i] = argv[j];
1819
1820 return cmd_record(i, rec_argv, NULL);
1821}
1822
David Ahernbf2575c2013-10-08 21:26:53 -06001823static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
1824
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001825static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
1826{
1827 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname",
1828 evlist->nr_entries);
1829 if (evsel == NULL)
1830 return;
1831
1832 if (perf_evsel__field(evsel, "pathname") == NULL) {
1833 perf_evsel__delete(evsel);
1834 return;
1835 }
1836
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001837 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001838 perf_evlist__add(evlist, evsel);
1839}
1840
Namhyung Kimf15eb532012-10-05 14:02:16 +09001841static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001842{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001843 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001844 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001845 int err = -1, i;
1846 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001847 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001848
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001849 trace->live = true;
1850
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001851 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001852 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001853 goto out;
1854 }
1855
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001856 if (perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, trace__sys_exit))
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301857 goto out_error_tp;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001858
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001859 perf_evlist__add_vfs_getname(evlist);
1860
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001861 if (trace->sched &&
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301862 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1863 trace__sched_stat_runtime))
1864 goto out_error_tp;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001865
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001866 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1867 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001868 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001869 goto out_delete_evlist;
1870 }
1871
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001872 err = trace__symbols_init(trace, evlist);
1873 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001874 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001875 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001876 }
1877
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001878 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001879
Namhyung Kimf15eb532012-10-05 14:02:16 +09001880 signal(SIGCHLD, sig_handler);
1881 signal(SIGINT, sig_handler);
1882
1883 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001884 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001885 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001886 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001887 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001888 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001889 }
1890 }
1891
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001892 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03001893 if (err < 0)
1894 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001895
1896 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1897 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001898 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001899 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001900 }
1901
1902 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001903
1904 if (forks)
1905 perf_evlist__start_workload(evlist);
1906
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001907 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001908again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001909 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001910
1911 for (i = 0; i < evlist->nr_mmaps; i++) {
1912 union perf_event *event;
1913
1914 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1915 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001916 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001917 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001918
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001919 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001920
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001921 err = perf_evlist__parse_sample(evlist, event, &sample);
1922 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001923 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001924 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001925 }
1926
David Ahern4bb09192013-09-04 12:37:43 -06001927 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001928 trace->base_time = sample.time;
1929
1930 if (type != PERF_RECORD_SAMPLE) {
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001931 trace__process_event(trace, trace->host, event, &sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001932 continue;
1933 }
1934
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001935 evsel = perf_evlist__id2evsel(evlist, sample.id);
1936 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001937 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001938 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001939 }
1940
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001941 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001942 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 -03001943 perf_evsel__name(evsel), sample.tid,
1944 sample.cpu, sample.raw_size);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001945 goto next_event;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001946 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001947
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001948 handler = evsel->handler;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001949 handler(trace, evsel, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001950next_event:
1951 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001952
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001953 if (interrupted)
1954 goto out_disable;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001955 }
1956 }
1957
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001958 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001959 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001960
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001961 if (poll(evlist->pollfd, evlist->nr_fds, timeout) > 0)
1962 goto again;
1963 } else {
1964 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001965 }
1966
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001967out_disable:
1968 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001969
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001970 if (!err) {
1971 if (trace->summary)
1972 trace__fprintf_thread_summary(trace, trace->output);
1973
1974 if (trace->show_tool_stats) {
1975 fprintf(trace->output, "Stats:\n "
1976 " vfs_getname : %" PRIu64 "\n"
1977 " proc_getname: %" PRIu64 "\n",
1978 trace->stats.vfs_getname,
1979 trace->stats.proc_getname);
1980 }
1981 }
David Ahernbf2575c2013-10-08 21:26:53 -06001982
Namhyung Kim3beb0862013-03-15 14:48:50 +09001983 perf_evlist__munmap(evlist);
1984out_close_evlist:
1985 perf_evlist__close(evlist);
1986out_delete_maps:
1987 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001988out_delete_evlist:
1989 perf_evlist__delete(evlist);
1990out:
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001991 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001992 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03001993{
1994 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03001995
1996out_error_tp:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03001997 perf_evlist__strerror_tp(evlist, errno, errbuf, sizeof(errbuf));
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03001998 goto out_error;
1999
2000out_error_open:
2001 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2002
2003out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002004 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302005 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002006}
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002007}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002008
David Ahern6810fc92013-08-28 22:29:52 -06002009static int trace__replay(struct trace *trace)
2010{
2011 const struct perf_evsel_str_handler handlers[] = {
2012 { "raw_syscalls:sys_enter", trace__sys_enter, },
2013 { "raw_syscalls:sys_exit", trace__sys_exit, },
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002014 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002015 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002016 struct perf_data_file file = {
2017 .path = input_name,
2018 .mode = PERF_DATA_MODE_READ,
2019 };
David Ahern6810fc92013-08-28 22:29:52 -06002020 struct perf_session *session;
2021 int err = -1;
2022
2023 trace->tool.sample = trace__process_sample;
2024 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002025 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002026 trace->tool.comm = perf_event__process_comm;
2027 trace->tool.exit = perf_event__process_exit;
2028 trace->tool.fork = perf_event__process_fork;
2029 trace->tool.attr = perf_event__process_attr;
2030 trace->tool.tracing_data = perf_event__process_tracing_data;
2031 trace->tool.build_id = perf_event__process_build_id;
2032
2033 trace->tool.ordered_samples = true;
2034 trace->tool.ordering_requires_timestamps = true;
2035
2036 /* add tid to output */
2037 trace->multiple_threads = true;
2038
2039 if (symbol__init() < 0)
2040 return -1;
2041
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002042 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002043 if (session == NULL)
2044 return -ENOMEM;
2045
David Ahern8fb598e2013-09-28 13:13:00 -06002046 trace->host = &session->machines.host;
2047
David Ahern6810fc92013-08-28 22:29:52 -06002048 err = perf_session__set_tracepoints_handlers(session, handlers);
2049 if (err)
2050 goto out;
2051
2052 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
2053 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
2054 goto out;
2055 }
2056
2057 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
2058 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
2059 goto out;
2060 }
2061
David Ahernbdc89662013-08-28 22:29:53 -06002062 err = parse_target_str(trace);
2063 if (err != 0)
2064 goto out;
2065
David Ahern6810fc92013-08-28 22:29:52 -06002066 setup_pager();
2067
2068 err = perf_session__process_events(session, &trace->tool);
2069 if (err)
2070 pr_err("Failed to process events, error %d", err);
2071
David Ahernbf2575c2013-10-08 21:26:53 -06002072 else if (trace->summary)
2073 trace__fprintf_thread_summary(trace, trace->output);
2074
David Ahern6810fc92013-08-28 22:29:52 -06002075out:
2076 perf_session__delete(session);
2077
2078 return err;
2079}
2080
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002081static size_t trace__fprintf_threads_header(FILE *fp)
2082{
2083 size_t printed;
2084
David Ahernbf2575c2013-10-08 21:26:53 -06002085 printed = fprintf(fp, "\n _____________________________________________________________________________\n");
2086 printed += fprintf(fp, " __) Summary of events (__\n\n");
2087 printed += fprintf(fp, " [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
2088 printed += fprintf(fp, " syscall count min max avg stddev\n");
2089 printed += fprintf(fp, " msec msec msec %%\n");
2090 printed += fprintf(fp, " _____________________________________________________________________________\n\n");
2091
2092 return printed;
2093}
2094
2095static size_t thread__dump_stats(struct thread_trace *ttrace,
2096 struct trace *trace, FILE *fp)
2097{
2098 struct stats *stats;
2099 size_t printed = 0;
2100 struct syscall *sc;
2101 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2102
2103 if (inode == NULL)
2104 return 0;
2105
2106 printed += fprintf(fp, "\n");
2107
2108 /* each int_node is a syscall */
2109 while (inode) {
2110 stats = inode->priv;
2111 if (stats) {
2112 double min = (double)(stats->min) / NSEC_PER_MSEC;
2113 double max = (double)(stats->max) / NSEC_PER_MSEC;
2114 double avg = avg_stats(stats);
2115 double pct;
2116 u64 n = (u64) stats->n;
2117
2118 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2119 avg /= NSEC_PER_MSEC;
2120
2121 sc = &trace->syscalls.table[inode->i];
2122 printed += fprintf(fp, "%24s %14s : ", "", sc->name);
2123 printed += fprintf(fp, "%5" PRIu64 " %8.3f %8.3f",
2124 n, min, max);
2125 printed += fprintf(fp, " %8.3f %6.2f\n", avg, pct);
2126 }
2127
2128 inode = intlist__next(inode);
2129 }
2130
2131 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002132
2133 return printed;
2134}
2135
David Ahern896cbb52013-09-28 13:12:59 -06002136/* struct used to pass data to per-thread function */
2137struct summary_data {
2138 FILE *fp;
2139 struct trace *trace;
2140 size_t printed;
2141};
2142
2143static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2144{
2145 struct summary_data *data = priv;
2146 FILE *fp = data->fp;
2147 size_t printed = data->printed;
2148 struct trace *trace = data->trace;
2149 struct thread_trace *ttrace = thread->priv;
2150 const char *color;
2151 double ratio;
2152
2153 if (ttrace == NULL)
2154 return 0;
2155
2156 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2157
2158 color = PERF_COLOR_NORMAL;
2159 if (ratio > 50.0)
2160 color = PERF_COLOR_RED;
2161 else if (ratio > 25.0)
2162 color = PERF_COLOR_GREEN;
2163 else if (ratio > 5.0)
2164 color = PERF_COLOR_YELLOW;
2165
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02002166 printed += color_fprintf(fp, color, "%20s", thread__comm_str(thread));
David Ahern896cbb52013-09-28 13:12:59 -06002167 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
2168 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
2169 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002170 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002171
2172 data->printed += printed;
2173
2174 return 0;
2175}
2176
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002177static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2178{
David Ahern896cbb52013-09-28 13:12:59 -06002179 struct summary_data data = {
2180 .fp = fp,
2181 .trace = trace
2182 };
2183 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002184
David Ahern896cbb52013-09-28 13:12:59 -06002185 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002186
David Ahern896cbb52013-09-28 13:12:59 -06002187 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002188}
2189
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002190static int trace__set_duration(const struct option *opt, const char *str,
2191 int unset __maybe_unused)
2192{
2193 struct trace *trace = opt->value;
2194
2195 trace->duration_filter = atof(str);
2196 return 0;
2197}
2198
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002199static int trace__open_output(struct trace *trace, const char *filename)
2200{
2201 struct stat st;
2202
2203 if (!stat(filename, &st) && st.st_size) {
2204 char oldname[PATH_MAX];
2205
2206 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2207 unlink(oldname);
2208 rename(filename, oldname);
2209 }
2210
2211 trace->output = fopen(filename, "w");
2212
2213 return trace->output == NULL ? -errno : 0;
2214}
2215
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002216int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2217{
2218 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002219 "perf trace [<options>] [<command>]",
2220 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002221 "perf trace record [<options>] [<command>]",
2222 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002223 NULL
2224 };
2225 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002226 .audit = {
2227 .machine = audit_detect_machine(),
2228 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2229 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002230 .syscalls = {
2231 . max = -1,
2232 },
2233 .opts = {
2234 .target = {
2235 .uid = UINT_MAX,
2236 .uses_mmap = true,
2237 },
2238 .user_freq = UINT_MAX,
2239 .user_interval = ULLONG_MAX,
2240 .no_delay = true,
2241 .mmap_pages = 1024,
2242 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002243 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002244 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002245 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002246 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002247 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002248 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002249 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2250 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002251 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002252 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
2253 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002254 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002255 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002256 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2257 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002258 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002259 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002260 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002261 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002262 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002263 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002264 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002265 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002266 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2267 "number of mmap data pages",
2268 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002269 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002270 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002271 OPT_CALLBACK(0, "duration", &trace, "float",
2272 "show only events with duration > N.M ms",
2273 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002274 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002275 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002276 OPT_BOOLEAN('T', "time", &trace.full_time,
2277 "Show full timestamp, not time relative to first start"),
David Ahernbf2575c2013-10-08 21:26:53 -06002278 OPT_BOOLEAN(0, "summary", &trace.summary,
2279 "Show syscall summary with statistics"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002280 OPT_END()
2281 };
2282 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002283 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002284
David Ahern5e2485b2013-09-28 13:13:01 -06002285 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
2286 return trace__record(argc-2, &argv[2]);
2287
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002288 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002289
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002290 if (output_name != NULL) {
2291 err = trace__open_output(&trace, output_name);
2292 if (err < 0) {
2293 perror("failed to create output file");
2294 goto out;
2295 }
2296 }
2297
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002298 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002299 const char *s = ev_qualifier_str;
2300
2301 trace.not_ev_qualifier = *s == '!';
2302 if (trace.not_ev_qualifier)
2303 ++s;
2304 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002305 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002306 fputs("Not enough memory to parse event qualifier",
2307 trace.output);
2308 err = -ENOMEM;
2309 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002310 }
2311 }
2312
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002313 err = perf_target__validate(&trace.opts.target);
2314 if (err) {
2315 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002316 fprintf(trace.output, "%s", bf);
2317 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002318 }
2319
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002320 err = perf_target__parse_uid(&trace.opts.target);
2321 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002322 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002323 fprintf(trace.output, "%s", bf);
2324 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002325 }
2326
Namhyung Kimf15eb532012-10-05 14:02:16 +09002327 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002328 trace.opts.target.system_wide = true;
2329
David Ahern6810fc92013-08-28 22:29:52 -06002330 if (input_name)
2331 err = trace__replay(&trace);
2332 else
2333 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002334
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002335out_close:
2336 if (output_name != NULL)
2337 fclose(trace.output);
2338out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002339 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002340}