blob: aeb6296a76bd550f9853cad3b395f2f4b5c27b42 [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
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300152static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300153{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300154 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300155
156 if (evsel) {
157 evsel->priv = malloc(sizeof(struct syscall_tp));
158
159 if (evsel->priv == NULL)
160 goto out_delete;
161
162 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
163 goto out_delete;
164
165 evsel->handler = handler;
166 }
167
168 return evsel;
169
170out_delete:
171 perf_evsel__delete_priv(evsel);
172 return NULL;
173}
174
175#define perf_evsel__sc_tp_uint(evsel, name, sample) \
176 ({ struct syscall_tp *fields = evsel->priv; \
177 fields->name.integer(&fields->name, sample); })
178
179#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
180 ({ struct syscall_tp *fields = evsel->priv; \
181 fields->name.pointer(&fields->name, sample); })
182
183static int perf_evlist__add_syscall_newtp(struct perf_evlist *evlist,
184 void *sys_enter_handler,
185 void *sys_exit_handler)
186{
187 int ret = -1;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300188 struct perf_evsel *sys_enter, *sys_exit;
189
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300190 sys_enter = perf_evsel__syscall_newtp("sys_enter", sys_enter_handler);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300191 if (sys_enter == NULL)
192 goto out;
193
194 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
195 goto out_delete_sys_enter;
196
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300197 sys_exit = perf_evsel__syscall_newtp("sys_exit", sys_exit_handler);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300198 if (sys_exit == NULL)
199 goto out_delete_sys_enter;
200
201 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
202 goto out_delete_sys_exit;
203
204 perf_evlist__add(evlist, sys_enter);
205 perf_evlist__add(evlist, sys_exit);
206
207 ret = 0;
208out:
209 return ret;
210
211out_delete_sys_exit:
212 perf_evsel__delete_priv(sys_exit);
213out_delete_sys_enter:
214 perf_evsel__delete_priv(sys_enter);
215 goto out;
216}
217
218
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300219struct syscall_arg {
220 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300221 struct thread *thread;
222 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300223 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300224 u8 idx;
225 u8 mask;
226};
227
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300228struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300229 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300230 int nr_entries;
231 const char **entries;
232};
233
234#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
235 .nr_entries = ARRAY_SIZE(array), \
236 .entries = array, \
237}
238
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300239#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
240 .offset = off, \
241 .nr_entries = ARRAY_SIZE(array), \
242 .entries = array, \
243}
244
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300245static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
246 const char *intfmt,
247 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300248{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300249 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300250 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300251
252 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300253 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300254
255 return scnprintf(bf, size, "%s", sa->entries[idx]);
256}
257
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300258static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
259 struct syscall_arg *arg)
260{
261 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
262}
263
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300264#define SCA_STRARRAY syscall_arg__scnprintf_strarray
265
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300266static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
267 struct syscall_arg *arg)
268{
269 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
270}
271
272#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
273
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300274static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
275 struct syscall_arg *arg);
276
277#define SCA_FD syscall_arg__scnprintf_fd
278
279static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
280 struct syscall_arg *arg)
281{
282 int fd = arg->val;
283
284 if (fd == AT_FDCWD)
285 return scnprintf(bf, size, "CWD");
286
287 return syscall_arg__scnprintf_fd(bf, size, arg);
288}
289
290#define SCA_FDAT syscall_arg__scnprintf_fd_at
291
292static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
293 struct syscall_arg *arg);
294
295#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
296
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300297static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300298 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300299{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300300 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300301}
302
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300303#define SCA_HEX syscall_arg__scnprintf_hex
304
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300305static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300306 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300307{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300308 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300309
310 if (prot == PROT_NONE)
311 return scnprintf(bf, size, "NONE");
312#define P_MMAP_PROT(n) \
313 if (prot & PROT_##n) { \
314 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
315 prot &= ~PROT_##n; \
316 }
317
318 P_MMAP_PROT(EXEC);
319 P_MMAP_PROT(READ);
320 P_MMAP_PROT(WRITE);
321#ifdef PROT_SEM
322 P_MMAP_PROT(SEM);
323#endif
324 P_MMAP_PROT(GROWSDOWN);
325 P_MMAP_PROT(GROWSUP);
326#undef P_MMAP_PROT
327
328 if (prot)
329 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
330
331 return printed;
332}
333
334#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
335
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300336static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300337 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300338{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300339 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300340
341#define P_MMAP_FLAG(n) \
342 if (flags & MAP_##n) { \
343 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
344 flags &= ~MAP_##n; \
345 }
346
347 P_MMAP_FLAG(SHARED);
348 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400349#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300350 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400351#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300352 P_MMAP_FLAG(ANONYMOUS);
353 P_MMAP_FLAG(DENYWRITE);
354 P_MMAP_FLAG(EXECUTABLE);
355 P_MMAP_FLAG(FILE);
356 P_MMAP_FLAG(FIXED);
357 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600358#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300359 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600360#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300361 P_MMAP_FLAG(LOCKED);
362 P_MMAP_FLAG(NONBLOCK);
363 P_MMAP_FLAG(NORESERVE);
364 P_MMAP_FLAG(POPULATE);
365 P_MMAP_FLAG(STACK);
366#ifdef MAP_UNINITIALIZED
367 P_MMAP_FLAG(UNINITIALIZED);
368#endif
369#undef P_MMAP_FLAG
370
371 if (flags)
372 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
373
374 return printed;
375}
376
377#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
378
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300379static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300380 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300381{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300382 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300383
384 switch (behavior) {
385#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
386 P_MADV_BHV(NORMAL);
387 P_MADV_BHV(RANDOM);
388 P_MADV_BHV(SEQUENTIAL);
389 P_MADV_BHV(WILLNEED);
390 P_MADV_BHV(DONTNEED);
391 P_MADV_BHV(REMOVE);
392 P_MADV_BHV(DONTFORK);
393 P_MADV_BHV(DOFORK);
394 P_MADV_BHV(HWPOISON);
395#ifdef MADV_SOFT_OFFLINE
396 P_MADV_BHV(SOFT_OFFLINE);
397#endif
398 P_MADV_BHV(MERGEABLE);
399 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600400#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300401 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600402#endif
403#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300404 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600405#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300406#ifdef MADV_DONTDUMP
407 P_MADV_BHV(DONTDUMP);
408#endif
409#ifdef MADV_DODUMP
410 P_MADV_BHV(DODUMP);
411#endif
412#undef P_MADV_PHV
413 default: break;
414 }
415
416 return scnprintf(bf, size, "%#x", behavior);
417}
418
419#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
420
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300421static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
422 struct syscall_arg *arg)
423{
424 int printed = 0, op = arg->val;
425
426 if (op == 0)
427 return scnprintf(bf, size, "NONE");
428#define P_CMD(cmd) \
429 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
430 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
431 op &= ~LOCK_##cmd; \
432 }
433
434 P_CMD(SH);
435 P_CMD(EX);
436 P_CMD(NB);
437 P_CMD(UN);
438 P_CMD(MAND);
439 P_CMD(RW);
440 P_CMD(READ);
441 P_CMD(WRITE);
442#undef P_OP
443
444 if (op)
445 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
446
447 return printed;
448}
449
450#define SCA_FLOCK syscall_arg__scnprintf_flock
451
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300452static 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 -0300453{
454 enum syscall_futex_args {
455 SCF_UADDR = (1 << 0),
456 SCF_OP = (1 << 1),
457 SCF_VAL = (1 << 2),
458 SCF_TIMEOUT = (1 << 3),
459 SCF_UADDR2 = (1 << 4),
460 SCF_VAL3 = (1 << 5),
461 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300462 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300463 int cmd = op & FUTEX_CMD_MASK;
464 size_t printed = 0;
465
466 switch (cmd) {
467#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300468 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
469 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
470 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
471 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
472 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
473 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300474 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300475 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
476 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
477 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
478 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
479 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300480 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
481 default: printed = scnprintf(bf, size, "%#x", cmd); break;
482 }
483
484 if (op & FUTEX_PRIVATE_FLAG)
485 printed += scnprintf(bf + printed, size - printed, "|PRIV");
486
487 if (op & FUTEX_CLOCK_REALTIME)
488 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
489
490 return printed;
491}
492
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300493#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
494
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300495static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
496static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300497
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300498static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
499static DEFINE_STRARRAY(itimers);
500
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300501static const char *whences[] = { "SET", "CUR", "END",
502#ifdef SEEK_DATA
503"DATA",
504#endif
505#ifdef SEEK_HOLE
506"HOLE",
507#endif
508};
509static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300510
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300511static const char *fcntl_cmds[] = {
512 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
513 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
514 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
515 "F_GETOWNER_UIDS",
516};
517static DEFINE_STRARRAY(fcntl_cmds);
518
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300519static const char *rlimit_resources[] = {
520 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
521 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
522 "RTTIME",
523};
524static DEFINE_STRARRAY(rlimit_resources);
525
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300526static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
527static DEFINE_STRARRAY(sighow);
528
David Ahern4f8c1b72013-09-22 19:45:00 -0600529static const char *clockid[] = {
530 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
531 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
532};
533static DEFINE_STRARRAY(clockid);
534
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300535static const char *socket_families[] = {
536 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
537 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
538 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
539 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
540 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
541 "ALG", "NFC", "VSOCK",
542};
543static DEFINE_STRARRAY(socket_families);
544
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300545#ifndef SOCK_TYPE_MASK
546#define SOCK_TYPE_MASK 0xf
547#endif
548
549static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
550 struct syscall_arg *arg)
551{
552 size_t printed;
553 int type = arg->val,
554 flags = type & ~SOCK_TYPE_MASK;
555
556 type &= SOCK_TYPE_MASK;
557 /*
558 * Can't use a strarray, MIPS may override for ABI reasons.
559 */
560 switch (type) {
561#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
562 P_SK_TYPE(STREAM);
563 P_SK_TYPE(DGRAM);
564 P_SK_TYPE(RAW);
565 P_SK_TYPE(RDM);
566 P_SK_TYPE(SEQPACKET);
567 P_SK_TYPE(DCCP);
568 P_SK_TYPE(PACKET);
569#undef P_SK_TYPE
570 default:
571 printed = scnprintf(bf, size, "%#x", type);
572 }
573
574#define P_SK_FLAG(n) \
575 if (flags & SOCK_##n) { \
576 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
577 flags &= ~SOCK_##n; \
578 }
579
580 P_SK_FLAG(CLOEXEC);
581 P_SK_FLAG(NONBLOCK);
582#undef P_SK_FLAG
583
584 if (flags)
585 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
586
587 return printed;
588}
589
590#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
591
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300592#ifndef MSG_PROBE
593#define MSG_PROBE 0x10
594#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600595#ifndef MSG_WAITFORONE
596#define MSG_WAITFORONE 0x10000
597#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300598#ifndef MSG_SENDPAGE_NOTLAST
599#define MSG_SENDPAGE_NOTLAST 0x20000
600#endif
601#ifndef MSG_FASTOPEN
602#define MSG_FASTOPEN 0x20000000
603#endif
604
605static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
606 struct syscall_arg *arg)
607{
608 int printed = 0, flags = arg->val;
609
610 if (flags == 0)
611 return scnprintf(bf, size, "NONE");
612#define P_MSG_FLAG(n) \
613 if (flags & MSG_##n) { \
614 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
615 flags &= ~MSG_##n; \
616 }
617
618 P_MSG_FLAG(OOB);
619 P_MSG_FLAG(PEEK);
620 P_MSG_FLAG(DONTROUTE);
621 P_MSG_FLAG(TRYHARD);
622 P_MSG_FLAG(CTRUNC);
623 P_MSG_FLAG(PROBE);
624 P_MSG_FLAG(TRUNC);
625 P_MSG_FLAG(DONTWAIT);
626 P_MSG_FLAG(EOR);
627 P_MSG_FLAG(WAITALL);
628 P_MSG_FLAG(FIN);
629 P_MSG_FLAG(SYN);
630 P_MSG_FLAG(CONFIRM);
631 P_MSG_FLAG(RST);
632 P_MSG_FLAG(ERRQUEUE);
633 P_MSG_FLAG(NOSIGNAL);
634 P_MSG_FLAG(MORE);
635 P_MSG_FLAG(WAITFORONE);
636 P_MSG_FLAG(SENDPAGE_NOTLAST);
637 P_MSG_FLAG(FASTOPEN);
638 P_MSG_FLAG(CMSG_CLOEXEC);
639#undef P_MSG_FLAG
640
641 if (flags)
642 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
643
644 return printed;
645}
646
647#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
648
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300649static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
650 struct syscall_arg *arg)
651{
652 size_t printed = 0;
653 int mode = arg->val;
654
655 if (mode == F_OK) /* 0 */
656 return scnprintf(bf, size, "F");
657#define P_MODE(n) \
658 if (mode & n##_OK) { \
659 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
660 mode &= ~n##_OK; \
661 }
662
663 P_MODE(R);
664 P_MODE(W);
665 P_MODE(X);
666#undef P_MODE
667
668 if (mode)
669 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
670
671 return printed;
672}
673
674#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
675
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300676static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300677 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300678{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300679 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300680
681 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300682 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300683
684 if (flags == 0)
685 return scnprintf(bf, size, "RDONLY");
686#define P_FLAG(n) \
687 if (flags & O_##n) { \
688 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
689 flags &= ~O_##n; \
690 }
691
692 P_FLAG(APPEND);
693 P_FLAG(ASYNC);
694 P_FLAG(CLOEXEC);
695 P_FLAG(CREAT);
696 P_FLAG(DIRECT);
697 P_FLAG(DIRECTORY);
698 P_FLAG(EXCL);
699 P_FLAG(LARGEFILE);
700 P_FLAG(NOATIME);
701 P_FLAG(NOCTTY);
702#ifdef O_NONBLOCK
703 P_FLAG(NONBLOCK);
704#elif O_NDELAY
705 P_FLAG(NDELAY);
706#endif
707#ifdef O_PATH
708 P_FLAG(PATH);
709#endif
710 P_FLAG(RDWR);
711#ifdef O_DSYNC
712 if ((flags & O_SYNC) == O_SYNC)
713 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
714 else {
715 P_FLAG(DSYNC);
716 }
717#else
718 P_FLAG(SYNC);
719#endif
720 P_FLAG(TRUNC);
721 P_FLAG(WRONLY);
722#undef P_FLAG
723
724 if (flags)
725 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
726
727 return printed;
728}
729
730#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
731
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300732static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
733 struct syscall_arg *arg)
734{
735 int printed = 0, flags = arg->val;
736
737 if (flags == 0)
738 return scnprintf(bf, size, "NONE");
739#define P_FLAG(n) \
740 if (flags & EFD_##n) { \
741 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
742 flags &= ~EFD_##n; \
743 }
744
745 P_FLAG(SEMAPHORE);
746 P_FLAG(CLOEXEC);
747 P_FLAG(NONBLOCK);
748#undef P_FLAG
749
750 if (flags)
751 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
752
753 return printed;
754}
755
756#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
757
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300758static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
759 struct syscall_arg *arg)
760{
761 int printed = 0, flags = arg->val;
762
763#define P_FLAG(n) \
764 if (flags & O_##n) { \
765 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
766 flags &= ~O_##n; \
767 }
768
769 P_FLAG(CLOEXEC);
770 P_FLAG(NONBLOCK);
771#undef P_FLAG
772
773 if (flags)
774 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
775
776 return printed;
777}
778
779#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
780
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300781static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
782{
783 int sig = arg->val;
784
785 switch (sig) {
786#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
787 P_SIGNUM(HUP);
788 P_SIGNUM(INT);
789 P_SIGNUM(QUIT);
790 P_SIGNUM(ILL);
791 P_SIGNUM(TRAP);
792 P_SIGNUM(ABRT);
793 P_SIGNUM(BUS);
794 P_SIGNUM(FPE);
795 P_SIGNUM(KILL);
796 P_SIGNUM(USR1);
797 P_SIGNUM(SEGV);
798 P_SIGNUM(USR2);
799 P_SIGNUM(PIPE);
800 P_SIGNUM(ALRM);
801 P_SIGNUM(TERM);
802 P_SIGNUM(STKFLT);
803 P_SIGNUM(CHLD);
804 P_SIGNUM(CONT);
805 P_SIGNUM(STOP);
806 P_SIGNUM(TSTP);
807 P_SIGNUM(TTIN);
808 P_SIGNUM(TTOU);
809 P_SIGNUM(URG);
810 P_SIGNUM(XCPU);
811 P_SIGNUM(XFSZ);
812 P_SIGNUM(VTALRM);
813 P_SIGNUM(PROF);
814 P_SIGNUM(WINCH);
815 P_SIGNUM(IO);
816 P_SIGNUM(PWR);
817 P_SIGNUM(SYS);
818 default: break;
819 }
820
821 return scnprintf(bf, size, "%#x", sig);
822}
823
824#define SCA_SIGNUM syscall_arg__scnprintf_signum
825
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300826#define TCGETS 0x5401
827
828static const char *tioctls[] = {
829 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
830 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
831 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
832 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
833 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
834 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
835 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
836 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
837 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
838 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
839 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
840 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
841 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
842 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
843 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
844};
845
846static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
847
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300848#define STRARRAY(arg, name, array) \
849 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
850 .arg_parm = { [arg] = &strarray__##array, }
851
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300852static struct syscall_fmt {
853 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300854 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300855 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300856 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300857 bool errmsg;
858 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300859 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300860} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300861 { .name = "access", .errmsg = true,
862 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300863 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300864 { .name = "brk", .hexret = true,
865 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600866 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300867 { .name = "close", .errmsg = true,
868 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300869 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300870 { .name = "dup", .errmsg = true,
871 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
872 { .name = "dup2", .errmsg = true,
873 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
874 { .name = "dup3", .errmsg = true,
875 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300876 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300877 { .name = "eventfd2", .errmsg = true,
878 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300879 { .name = "faccessat", .errmsg = true,
880 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
881 { .name = "fadvise64", .errmsg = true,
882 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
883 { .name = "fallocate", .errmsg = true,
884 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
885 { .name = "fchdir", .errmsg = true,
886 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
887 { .name = "fchmod", .errmsg = true,
888 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
889 { .name = "fchmodat", .errmsg = true,
890 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
891 { .name = "fchown", .errmsg = true,
892 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
893 { .name = "fchownat", .errmsg = true,
894 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
895 { .name = "fcntl", .errmsg = true,
896 .arg_scnprintf = { [0] = SCA_FD, /* fd */
897 [1] = SCA_STRARRAY, /* cmd */ },
898 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
899 { .name = "fdatasync", .errmsg = true,
900 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300901 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300902 .arg_scnprintf = { [0] = SCA_FD, /* fd */
903 [1] = SCA_FLOCK, /* cmd */ }, },
904 { .name = "fsetxattr", .errmsg = true,
905 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
906 { .name = "fstat", .errmsg = true, .alias = "newfstat",
907 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
908 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
909 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
910 { .name = "fstatfs", .errmsg = true,
911 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
912 { .name = "fsync", .errmsg = true,
913 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
914 { .name = "ftruncate", .errmsg = true,
915 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300916 { .name = "futex", .errmsg = true,
917 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300918 { .name = "futimesat", .errmsg = true,
919 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
920 { .name = "getdents", .errmsg = true,
921 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
922 { .name = "getdents64", .errmsg = true,
923 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300924 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
925 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300926 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300927 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300928 [1] = SCA_STRHEXARRAY, /* cmd */
929 [2] = SCA_HEX, /* arg */ },
930 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300931 { .name = "kill", .errmsg = true,
932 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300933 { .name = "linkat", .errmsg = true,
934 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
935 { .name = "lseek", .errmsg = true,
936 .arg_scnprintf = { [0] = SCA_FD, /* fd */
937 [2] = SCA_STRARRAY, /* whence */ },
938 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300939 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300940 { .name = "madvise", .errmsg = true,
941 .arg_scnprintf = { [0] = SCA_HEX, /* start */
942 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300943 { .name = "mkdirat", .errmsg = true,
944 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
945 { .name = "mknodat", .errmsg = true,
946 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300947 { .name = "mlock", .errmsg = true,
948 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
949 { .name = "mlockall", .errmsg = true,
950 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300951 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300952 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300953 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +0900954 [3] = SCA_MMAP_FLAGS, /* flags */
955 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300956 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300957 .arg_scnprintf = { [0] = SCA_HEX, /* start */
958 [2] = SCA_MMAP_PROT, /* prot */ }, },
959 { .name = "mremap", .hexret = true,
960 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
961 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300962 { .name = "munlock", .errmsg = true,
963 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300964 { .name = "munmap", .errmsg = true,
965 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300966 { .name = "name_to_handle_at", .errmsg = true,
967 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
968 { .name = "newfstatat", .errmsg = true,
969 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300970 { .name = "open", .errmsg = true,
971 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300972 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300973 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
974 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300975 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300976 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
977 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300978 { .name = "pipe2", .errmsg = true,
979 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300980 { .name = "poll", .errmsg = true, .timeout = true, },
981 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300982 { .name = "pread", .errmsg = true, .alias = "pread64",
983 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
984 { .name = "preadv", .errmsg = true, .alias = "pread",
985 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300986 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300987 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
988 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
989 { .name = "pwritev", .errmsg = true,
990 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
991 { .name = "read", .errmsg = true,
992 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
993 { .name = "readlinkat", .errmsg = true,
994 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
995 { .name = "readv", .errmsg = true,
996 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300997 { .name = "recvfrom", .errmsg = true,
998 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
999 { .name = "recvmmsg", .errmsg = true,
1000 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1001 { .name = "recvmsg", .errmsg = true,
1002 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001003 { .name = "renameat", .errmsg = true,
1004 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001005 { .name = "rt_sigaction", .errmsg = true,
1006 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001007 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001008 { .name = "rt_sigqueueinfo", .errmsg = true,
1009 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1010 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1011 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001012 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001013 { .name = "sendmmsg", .errmsg = true,
1014 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1015 { .name = "sendmsg", .errmsg = true,
1016 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
1017 { .name = "sendto", .errmsg = true,
1018 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001019 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1020 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001021 { .name = "shutdown", .errmsg = true,
1022 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001023 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001024 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1025 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001026 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001027 { .name = "socketpair", .errmsg = true,
1028 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1029 [1] = SCA_SK_TYPE, /* type */ },
1030 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001031 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001032 { .name = "symlinkat", .errmsg = true,
1033 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001034 { .name = "tgkill", .errmsg = true,
1035 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1036 { .name = "tkill", .errmsg = true,
1037 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001038 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001039 { .name = "unlinkat", .errmsg = true,
1040 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1041 { .name = "utimensat", .errmsg = true,
1042 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
1043 { .name = "write", .errmsg = true,
1044 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1045 { .name = "writev", .errmsg = true,
1046 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001047};
1048
1049static int syscall_fmt__cmp(const void *name, const void *fmtp)
1050{
1051 const struct syscall_fmt *fmt = fmtp;
1052 return strcmp(name, fmt->name);
1053}
1054
1055static struct syscall_fmt *syscall_fmt__find(const char *name)
1056{
1057 const int nmemb = ARRAY_SIZE(syscall_fmts);
1058 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1059}
1060
1061struct syscall {
1062 struct event_format *tp_format;
1063 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001064 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001065 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001066 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001067 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001068};
1069
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001070static size_t fprintf_duration(unsigned long t, FILE *fp)
1071{
1072 double duration = (double)t / NSEC_PER_MSEC;
1073 size_t printed = fprintf(fp, "(");
1074
1075 if (duration >= 1.0)
1076 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1077 else if (duration >= 0.01)
1078 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1079 else
1080 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001081 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001082}
1083
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001084struct thread_trace {
1085 u64 entry_time;
1086 u64 exit_time;
1087 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001088 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001089 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001090 double runtime_ms;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001091 struct {
1092 int max;
1093 char **table;
1094 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001095
1096 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001097};
1098
1099static struct thread_trace *thread_trace__new(void)
1100{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001101 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1102
1103 if (ttrace)
1104 ttrace->paths.max = -1;
1105
David Ahernbf2575c2013-10-08 21:26:53 -06001106 ttrace->syscall_stats = intlist__new(NULL);
1107
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001108 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001109}
1110
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001111static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001112{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001113 struct thread_trace *ttrace;
1114
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001115 if (thread == NULL)
1116 goto fail;
1117
1118 if (thread->priv == NULL)
1119 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001120
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001121 if (thread->priv == NULL)
1122 goto fail;
1123
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001124 ttrace = thread->priv;
1125 ++ttrace->nr_events;
1126
1127 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001128fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001129 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001130 "WARNING: not enough memory, dropping samples!\n");
1131 return NULL;
1132}
1133
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001134struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001135 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001136 struct {
1137 int machine;
1138 int open_id;
1139 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001140 struct {
1141 int max;
1142 struct syscall *table;
1143 } syscalls;
1144 struct perf_record_opts opts;
David Ahern8fb598e2013-09-28 13:13:00 -06001145 struct machine *host;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001146 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -06001147 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001148 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001149 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001150 struct strlist *ev_qualifier;
1151 bool not_ev_qualifier;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001152 bool live;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001153 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -06001154 struct intlist *tid_list;
1155 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001156 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001157 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001158 bool summary;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001159 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001160 bool show_tool_stats;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001161 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001162 double runtime_ms;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001163 struct {
1164 u64 vfs_getname, proc_getname;
1165 } stats;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001166};
1167
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001168static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001169{
1170 struct thread_trace *ttrace = thread->priv;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001171
1172 if (fd > ttrace->paths.max) {
1173 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1174
1175 if (npath == NULL)
1176 return -1;
1177
1178 if (ttrace->paths.max != -1) {
1179 memset(npath + ttrace->paths.max + 1, 0,
1180 (fd - ttrace->paths.max) * sizeof(char *));
1181 } else {
1182 memset(npath, 0, (fd + 1) * sizeof(char *));
1183 }
1184
1185 ttrace->paths.table = npath;
1186 ttrace->paths.max = fd;
1187 }
1188
1189 ttrace->paths.table[fd] = strdup(pathname);
1190
1191 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1192}
1193
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001194static int thread__read_fd_path(struct thread *thread, int fd)
1195{
1196 char linkname[PATH_MAX], pathname[PATH_MAX];
1197 struct stat st;
1198 int ret;
1199
1200 if (thread->pid_ == thread->tid) {
1201 scnprintf(linkname, sizeof(linkname),
1202 "/proc/%d/fd/%d", thread->pid_, fd);
1203 } else {
1204 scnprintf(linkname, sizeof(linkname),
1205 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1206 }
1207
1208 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1209 return -1;
1210
1211 ret = readlink(linkname, pathname, sizeof(pathname));
1212
1213 if (ret < 0 || ret > st.st_size)
1214 return -1;
1215
1216 pathname[ret] = '\0';
1217 return trace__set_fd_pathname(thread, fd, pathname);
1218}
1219
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001220static const char *thread__fd_path(struct thread *thread, int fd,
1221 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001222{
1223 struct thread_trace *ttrace = thread->priv;
1224
1225 if (ttrace == NULL)
1226 return NULL;
1227
1228 if (fd < 0)
1229 return NULL;
1230
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001231 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL))
1232 if (!trace->live)
1233 return NULL;
1234 ++trace->stats.proc_getname;
1235 if (thread__read_fd_path(thread, fd)) {
1236 return NULL;
1237 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001238
1239 return ttrace->paths.table[fd];
1240}
1241
1242static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1243 struct syscall_arg *arg)
1244{
1245 int fd = arg->val;
1246 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001247 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001248
1249 if (path)
1250 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1251
1252 return printed;
1253}
1254
1255static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1256 struct syscall_arg *arg)
1257{
1258 int fd = arg->val;
1259 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1260 struct thread_trace *ttrace = arg->thread->priv;
1261
1262 if (ttrace && fd >= 0 && fd <= ttrace->paths.max) {
1263 free(ttrace->paths.table[fd]);
1264 ttrace->paths.table[fd] = NULL;
1265 }
1266
1267 return printed;
1268}
1269
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001270static bool trace__filter_duration(struct trace *trace, double t)
1271{
1272 return t < (trace->duration_filter * NSEC_PER_MSEC);
1273}
1274
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001275static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1276{
1277 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1278
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001279 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001280}
1281
Namhyung Kimf15eb532012-10-05 14:02:16 +09001282static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001283static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001284
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001285static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001286{
1287 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001288 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001289}
1290
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001291static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001292 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001293{
1294 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001295 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001296
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001297 if (trace->multiple_threads) {
1298 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001299 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001300 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001301 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001302
1303 return printed;
1304}
1305
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001306static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001307 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001308{
1309 int ret = 0;
1310
1311 switch (event->header.type) {
1312 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001313 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001314 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001315 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001316 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001317 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001318 break;
1319 }
1320
1321 return ret;
1322}
1323
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001324static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001325 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001326 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001327 struct machine *machine)
1328{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001329 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001330 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001331}
1332
1333static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1334{
1335 int err = symbol__init();
1336
1337 if (err)
1338 return err;
1339
David Ahern8fb598e2013-09-28 13:13:00 -06001340 trace->host = machine__new_host();
1341 if (trace->host == NULL)
1342 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001343
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001344 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
1345 evlist->threads, trace__tool_process, false);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001346 if (err)
1347 symbol__exit();
1348
1349 return err;
1350}
1351
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001352static int syscall__set_arg_fmts(struct syscall *sc)
1353{
1354 struct format_field *field;
1355 int idx = 0;
1356
1357 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1358 if (sc->arg_scnprintf == NULL)
1359 return -1;
1360
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001361 if (sc->fmt)
1362 sc->arg_parm = sc->fmt->arg_parm;
1363
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001364 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001365 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1366 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1367 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001368 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1369 ++idx;
1370 }
1371
1372 return 0;
1373}
1374
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001375static int trace__read_syscall_info(struct trace *trace, int id)
1376{
1377 char tp_name[128];
1378 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001379 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001380
1381 if (name == NULL)
1382 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001383
1384 if (id > trace->syscalls.max) {
1385 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1386
1387 if (nsyscalls == NULL)
1388 return -1;
1389
1390 if (trace->syscalls.max != -1) {
1391 memset(nsyscalls + trace->syscalls.max + 1, 0,
1392 (id - trace->syscalls.max) * sizeof(*sc));
1393 } else {
1394 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1395 }
1396
1397 trace->syscalls.table = nsyscalls;
1398 trace->syscalls.max = id;
1399 }
1400
1401 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001402 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001403
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001404 if (trace->ev_qualifier) {
1405 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1406
1407 if (!(in ^ trace->not_ev_qualifier)) {
1408 sc->filtered = true;
1409 /*
1410 * No need to do read tracepoint information since this will be
1411 * filtered out.
1412 */
1413 return 0;
1414 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001415 }
1416
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001417 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001418
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001419 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
1420 sc->tp_format = event_format__new("syscalls", tp_name);
1421
1422 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1423 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
1424 sc->tp_format = event_format__new("syscalls", tp_name);
1425 }
1426
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001427 if (sc->tp_format == NULL)
1428 return -1;
1429
1430 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001431}
1432
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001433static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001434 unsigned long *args, struct trace *trace,
1435 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001436{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001437 size_t printed = 0;
1438
1439 if (sc->tp_format != NULL) {
1440 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001441 u8 bit = 1;
1442 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001443 .idx = 0,
1444 .mask = 0,
1445 .trace = trace,
1446 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001447 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001448
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001449 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001450 field = field->next, ++arg.idx, bit <<= 1) {
1451 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001452 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001453 /*
1454 * Suppress this argument if its value is zero and
1455 * and we don't have a string associated in an
1456 * strarray for it.
1457 */
1458 if (args[arg.idx] == 0 &&
1459 !(sc->arg_scnprintf &&
1460 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1461 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001462 continue;
1463
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001464 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001465 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001466 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1467 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001468 if (sc->arg_parm)
1469 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001470 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1471 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001472 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001473 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001474 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001475 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001476 }
1477 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001478 int i = 0;
1479
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001480 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001481 printed += scnprintf(bf + printed, size - printed,
1482 "%sarg%d: %ld",
1483 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001484 ++i;
1485 }
1486 }
1487
1488 return printed;
1489}
1490
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001491typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1492 struct perf_sample *sample);
1493
1494static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001495 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001496{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001497
1498 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001499
1500 /*
1501 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1502 * before that, leaving at a higher verbosity level till that is
1503 * explained. Reproduced with plain ftrace with:
1504 *
1505 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1506 * grep "NR -1 " /t/trace_pipe
1507 *
1508 * After generating some load on the machine.
1509 */
1510 if (verbose > 1) {
1511 static u64 n;
1512 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1513 id, perf_evsel__name(evsel), ++n);
1514 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001515 return NULL;
1516 }
1517
1518 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1519 trace__read_syscall_info(trace, id))
1520 goto out_cant_read;
1521
1522 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1523 goto out_cant_read;
1524
1525 return &trace->syscalls.table[id];
1526
1527out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001528 if (verbose) {
1529 fprintf(trace->output, "Problems reading syscall %d", id);
1530 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1531 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1532 fputs(" information\n", trace->output);
1533 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001534 return NULL;
1535}
1536
David Ahernbf2575c2013-10-08 21:26:53 -06001537static void thread__update_stats(struct thread_trace *ttrace,
1538 int id, struct perf_sample *sample)
1539{
1540 struct int_node *inode;
1541 struct stats *stats;
1542 u64 duration = 0;
1543
1544 inode = intlist__findnew(ttrace->syscall_stats, id);
1545 if (inode == NULL)
1546 return;
1547
1548 stats = inode->priv;
1549 if (stats == NULL) {
1550 stats = malloc(sizeof(struct stats));
1551 if (stats == NULL)
1552 return;
1553 init_stats(stats);
1554 inode->priv = stats;
1555 }
1556
1557 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1558 duration = sample->time - ttrace->entry_time;
1559
1560 update_stats(stats, duration);
1561}
1562
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001563static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1564 struct perf_sample *sample)
1565{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001566 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001567 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001568 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001569 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001570 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001571 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001572 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001573
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001574 if (sc == NULL)
1575 return -1;
1576
1577 if (sc->filtered)
1578 return 0;
1579
David Ahern8fb598e2013-09-28 13:13:00 -06001580 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001581 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001582 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001583 return -1;
1584
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001585 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001586 ttrace = thread->priv;
1587
1588 if (ttrace->entry_str == NULL) {
1589 ttrace->entry_str = malloc(1024);
1590 if (!ttrace->entry_str)
1591 return -1;
1592 }
1593
1594 ttrace->entry_time = sample->time;
1595 msg = ttrace->entry_str;
1596 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1597
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001598 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1599 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001600
1601 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001602 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001603 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1604 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001605 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001606 } else
1607 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001608
1609 return 0;
1610}
1611
1612static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1613 struct perf_sample *sample)
1614{
1615 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001616 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001617 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001618 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001619 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001620 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001621
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001622 if (sc == NULL)
1623 return -1;
1624
1625 if (sc->filtered)
1626 return 0;
1627
David Ahern8fb598e2013-09-28 13:13:00 -06001628 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001629 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001630 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001631 return -1;
1632
David Ahernbf2575c2013-10-08 21:26:53 -06001633 if (trace->summary)
1634 thread__update_stats(ttrace, id, sample);
1635
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001636 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001637
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001638 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1639 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1640 trace->last_vfs_getname = NULL;
1641 ++trace->stats.vfs_getname;
1642 }
1643
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001644 ttrace = thread->priv;
1645
1646 ttrace->exit_time = sample->time;
1647
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001648 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001649 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001650 if (trace__filter_duration(trace, duration))
1651 goto out;
1652 } else if (trace->duration_filter)
1653 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001654
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001655 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001656
1657 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001658 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001659 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001660 fprintf(trace->output, " ... [");
1661 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1662 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001663 }
1664
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001665 if (sc->fmt == NULL) {
1666signed_print:
1667 fprintf(trace->output, ") = %d", ret);
1668 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001669 char bf[256];
1670 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1671 *e = audit_errno_to_name(-ret);
1672
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001673 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001674 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001675 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001676 else if (sc->fmt->hexret)
1677 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001678 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001679 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001680
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001681 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001682out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001683 ttrace->entry_pending = false;
1684
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001685 return 0;
1686}
1687
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001688static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1689 struct perf_sample *sample)
1690{
1691 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1692 return 0;
1693}
1694
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001695static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1696 struct perf_sample *sample)
1697{
1698 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1699 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001700 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001701 sample->pid,
1702 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001703 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001704
1705 if (ttrace == NULL)
1706 goto out_dump;
1707
1708 ttrace->runtime_ms += runtime_ms;
1709 trace->runtime_ms += runtime_ms;
1710 return 0;
1711
1712out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001713 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001714 evsel->name,
1715 perf_evsel__strval(evsel, sample, "comm"),
1716 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1717 runtime,
1718 perf_evsel__intval(evsel, sample, "vruntime"));
1719 return 0;
1720}
1721
David Ahernbdc89662013-08-28 22:29:53 -06001722static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1723{
1724 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1725 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1726 return false;
1727
1728 if (trace->pid_list || trace->tid_list)
1729 return true;
1730
1731 return false;
1732}
1733
David Ahern6810fc92013-08-28 22:29:52 -06001734static int trace__process_sample(struct perf_tool *tool,
1735 union perf_event *event __maybe_unused,
1736 struct perf_sample *sample,
1737 struct perf_evsel *evsel,
1738 struct machine *machine __maybe_unused)
1739{
1740 struct trace *trace = container_of(tool, struct trace, tool);
1741 int err = 0;
1742
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001743 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001744
David Ahernbdc89662013-08-28 22:29:53 -06001745 if (skip_sample(trace, sample))
1746 return 0;
1747
David Ahern4bb09192013-09-04 12:37:43 -06001748 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001749 trace->base_time = sample->time;
1750
1751 if (handler)
1752 handler(trace, evsel, sample);
1753
1754 return err;
1755}
1756
1757static bool
1758perf_session__has_tp(struct perf_session *session, const char *name)
1759{
1760 struct perf_evsel *evsel;
1761
1762 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1763
1764 return evsel != NULL;
1765}
1766
David Ahernbdc89662013-08-28 22:29:53 -06001767static int parse_target_str(struct trace *trace)
1768{
1769 if (trace->opts.target.pid) {
1770 trace->pid_list = intlist__new(trace->opts.target.pid);
1771 if (trace->pid_list == NULL) {
1772 pr_err("Error parsing process id string\n");
1773 return -EINVAL;
1774 }
1775 }
1776
1777 if (trace->opts.target.tid) {
1778 trace->tid_list = intlist__new(trace->opts.target.tid);
1779 if (trace->tid_list == NULL) {
1780 pr_err("Error parsing thread id string\n");
1781 return -EINVAL;
1782 }
1783 }
1784
1785 return 0;
1786}
1787
David Ahern5e2485b2013-09-28 13:13:01 -06001788static int trace__record(int argc, const char **argv)
1789{
1790 unsigned int rec_argc, i, j;
1791 const char **rec_argv;
1792 const char * const record_args[] = {
1793 "record",
1794 "-R",
1795 "-m", "1024",
1796 "-c", "1",
1797 "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit",
1798 };
1799
1800 rec_argc = ARRAY_SIZE(record_args) + argc;
1801 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1802
1803 if (rec_argv == NULL)
1804 return -ENOMEM;
1805
1806 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1807 rec_argv[i] = record_args[i];
1808
1809 for (j = 0; j < (unsigned int)argc; j++, i++)
1810 rec_argv[i] = argv[j];
1811
1812 return cmd_record(i, rec_argv, NULL);
1813}
1814
David Ahernbf2575c2013-10-08 21:26:53 -06001815static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
1816
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001817static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
1818{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03001819 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001820 if (evsel == NULL)
1821 return;
1822
1823 if (perf_evsel__field(evsel, "pathname") == NULL) {
1824 perf_evsel__delete(evsel);
1825 return;
1826 }
1827
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001828 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001829 perf_evlist__add(evlist, evsel);
1830}
1831
Namhyung Kimf15eb532012-10-05 14:02:16 +09001832static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001833{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001834 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001835 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001836 int err = -1, i;
1837 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001838 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001839
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001840 trace->live = true;
1841
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001842 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001843 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001844 goto out;
1845 }
1846
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001847 if (perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, trace__sys_exit))
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301848 goto out_error_tp;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001849
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001850 perf_evlist__add_vfs_getname(evlist);
1851
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001852 if (trace->sched &&
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301853 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1854 trace__sched_stat_runtime))
1855 goto out_error_tp;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001856
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001857 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1858 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001859 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001860 goto out_delete_evlist;
1861 }
1862
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001863 err = trace__symbols_init(trace, evlist);
1864 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001865 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001866 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001867 }
1868
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001869 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001870
Namhyung Kimf15eb532012-10-05 14:02:16 +09001871 signal(SIGCHLD, sig_handler);
1872 signal(SIGINT, sig_handler);
1873
1874 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001875 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001876 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001877 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001878 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001879 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001880 }
1881 }
1882
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001883 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03001884 if (err < 0)
1885 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001886
1887 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1888 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001889 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001890 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001891 }
1892
1893 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001894
1895 if (forks)
1896 perf_evlist__start_workload(evlist);
1897
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001898 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001899again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001900 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001901
1902 for (i = 0; i < evlist->nr_mmaps; i++) {
1903 union perf_event *event;
1904
1905 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1906 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001907 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001908 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001909
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001910 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001911
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001912 err = perf_evlist__parse_sample(evlist, event, &sample);
1913 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001914 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001915 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001916 }
1917
David Ahern4bb09192013-09-04 12:37:43 -06001918 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001919 trace->base_time = sample.time;
1920
1921 if (type != PERF_RECORD_SAMPLE) {
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001922 trace__process_event(trace, trace->host, event, &sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001923 continue;
1924 }
1925
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001926 evsel = perf_evlist__id2evsel(evlist, sample.id);
1927 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001928 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001929 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001930 }
1931
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001932 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001933 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 -03001934 perf_evsel__name(evsel), sample.tid,
1935 sample.cpu, sample.raw_size);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001936 goto next_event;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001937 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001938
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001939 handler = evsel->handler;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001940 handler(trace, evsel, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001941next_event:
1942 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001943
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001944 if (interrupted)
1945 goto out_disable;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001946 }
1947 }
1948
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001949 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001950 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001951
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001952 if (poll(evlist->pollfd, evlist->nr_fds, timeout) > 0)
1953 goto again;
1954 } else {
1955 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001956 }
1957
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001958out_disable:
1959 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001960
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001961 if (!err) {
1962 if (trace->summary)
1963 trace__fprintf_thread_summary(trace, trace->output);
1964
1965 if (trace->show_tool_stats) {
1966 fprintf(trace->output, "Stats:\n "
1967 " vfs_getname : %" PRIu64 "\n"
1968 " proc_getname: %" PRIu64 "\n",
1969 trace->stats.vfs_getname,
1970 trace->stats.proc_getname);
1971 }
1972 }
David Ahernbf2575c2013-10-08 21:26:53 -06001973
Namhyung Kim3beb0862013-03-15 14:48:50 +09001974 perf_evlist__munmap(evlist);
1975out_close_evlist:
1976 perf_evlist__close(evlist);
1977out_delete_maps:
1978 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001979out_delete_evlist:
1980 perf_evlist__delete(evlist);
1981out:
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001982 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001983 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03001984{
1985 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03001986
1987out_error_tp:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03001988 perf_evlist__strerror_tp(evlist, errno, errbuf, sizeof(errbuf));
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03001989 goto out_error;
1990
1991out_error_open:
1992 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
1993
1994out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03001995 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301996 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001997}
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03001998}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001999
David Ahern6810fc92013-08-28 22:29:52 -06002000static int trace__replay(struct trace *trace)
2001{
2002 const struct perf_evsel_str_handler handlers[] = {
2003 { "raw_syscalls:sys_enter", trace__sys_enter, },
2004 { "raw_syscalls:sys_exit", trace__sys_exit, },
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002005 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002006 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002007 struct perf_data_file file = {
2008 .path = input_name,
2009 .mode = PERF_DATA_MODE_READ,
2010 };
David Ahern6810fc92013-08-28 22:29:52 -06002011 struct perf_session *session;
2012 int err = -1;
2013
2014 trace->tool.sample = trace__process_sample;
2015 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002016 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002017 trace->tool.comm = perf_event__process_comm;
2018 trace->tool.exit = perf_event__process_exit;
2019 trace->tool.fork = perf_event__process_fork;
2020 trace->tool.attr = perf_event__process_attr;
2021 trace->tool.tracing_data = perf_event__process_tracing_data;
2022 trace->tool.build_id = perf_event__process_build_id;
2023
2024 trace->tool.ordered_samples = true;
2025 trace->tool.ordering_requires_timestamps = true;
2026
2027 /* add tid to output */
2028 trace->multiple_threads = true;
2029
2030 if (symbol__init() < 0)
2031 return -1;
2032
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002033 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002034 if (session == NULL)
2035 return -ENOMEM;
2036
David Ahern8fb598e2013-09-28 13:13:00 -06002037 trace->host = &session->machines.host;
2038
David Ahern6810fc92013-08-28 22:29:52 -06002039 err = perf_session__set_tracepoints_handlers(session, handlers);
2040 if (err)
2041 goto out;
2042
2043 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
2044 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
2045 goto out;
2046 }
2047
2048 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
2049 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
2050 goto out;
2051 }
2052
David Ahernbdc89662013-08-28 22:29:53 -06002053 err = parse_target_str(trace);
2054 if (err != 0)
2055 goto out;
2056
David Ahern6810fc92013-08-28 22:29:52 -06002057 setup_pager();
2058
2059 err = perf_session__process_events(session, &trace->tool);
2060 if (err)
2061 pr_err("Failed to process events, error %d", err);
2062
David Ahernbf2575c2013-10-08 21:26:53 -06002063 else if (trace->summary)
2064 trace__fprintf_thread_summary(trace, trace->output);
2065
David Ahern6810fc92013-08-28 22:29:52 -06002066out:
2067 perf_session__delete(session);
2068
2069 return err;
2070}
2071
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002072static size_t trace__fprintf_threads_header(FILE *fp)
2073{
2074 size_t printed;
2075
David Ahernbf2575c2013-10-08 21:26:53 -06002076 printed = fprintf(fp, "\n _____________________________________________________________________________\n");
2077 printed += fprintf(fp, " __) Summary of events (__\n\n");
2078 printed += fprintf(fp, " [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
2079 printed += fprintf(fp, " syscall count min max avg stddev\n");
2080 printed += fprintf(fp, " msec msec msec %%\n");
2081 printed += fprintf(fp, " _____________________________________________________________________________\n\n");
2082
2083 return printed;
2084}
2085
2086static size_t thread__dump_stats(struct thread_trace *ttrace,
2087 struct trace *trace, FILE *fp)
2088{
2089 struct stats *stats;
2090 size_t printed = 0;
2091 struct syscall *sc;
2092 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2093
2094 if (inode == NULL)
2095 return 0;
2096
2097 printed += fprintf(fp, "\n");
2098
2099 /* each int_node is a syscall */
2100 while (inode) {
2101 stats = inode->priv;
2102 if (stats) {
2103 double min = (double)(stats->min) / NSEC_PER_MSEC;
2104 double max = (double)(stats->max) / NSEC_PER_MSEC;
2105 double avg = avg_stats(stats);
2106 double pct;
2107 u64 n = (u64) stats->n;
2108
2109 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2110 avg /= NSEC_PER_MSEC;
2111
2112 sc = &trace->syscalls.table[inode->i];
2113 printed += fprintf(fp, "%24s %14s : ", "", sc->name);
2114 printed += fprintf(fp, "%5" PRIu64 " %8.3f %8.3f",
2115 n, min, max);
2116 printed += fprintf(fp, " %8.3f %6.2f\n", avg, pct);
2117 }
2118
2119 inode = intlist__next(inode);
2120 }
2121
2122 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002123
2124 return printed;
2125}
2126
David Ahern896cbb52013-09-28 13:12:59 -06002127/* struct used to pass data to per-thread function */
2128struct summary_data {
2129 FILE *fp;
2130 struct trace *trace;
2131 size_t printed;
2132};
2133
2134static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2135{
2136 struct summary_data *data = priv;
2137 FILE *fp = data->fp;
2138 size_t printed = data->printed;
2139 struct trace *trace = data->trace;
2140 struct thread_trace *ttrace = thread->priv;
2141 const char *color;
2142 double ratio;
2143
2144 if (ttrace == NULL)
2145 return 0;
2146
2147 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2148
2149 color = PERF_COLOR_NORMAL;
2150 if (ratio > 50.0)
2151 color = PERF_COLOR_RED;
2152 else if (ratio > 25.0)
2153 color = PERF_COLOR_GREEN;
2154 else if (ratio > 5.0)
2155 color = PERF_COLOR_YELLOW;
2156
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02002157 printed += color_fprintf(fp, color, "%20s", thread__comm_str(thread));
David Ahern896cbb52013-09-28 13:12:59 -06002158 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
2159 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
2160 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002161 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002162
2163 data->printed += printed;
2164
2165 return 0;
2166}
2167
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002168static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2169{
David Ahern896cbb52013-09-28 13:12:59 -06002170 struct summary_data data = {
2171 .fp = fp,
2172 .trace = trace
2173 };
2174 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002175
David Ahern896cbb52013-09-28 13:12:59 -06002176 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002177
David Ahern896cbb52013-09-28 13:12:59 -06002178 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002179}
2180
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002181static int trace__set_duration(const struct option *opt, const char *str,
2182 int unset __maybe_unused)
2183{
2184 struct trace *trace = opt->value;
2185
2186 trace->duration_filter = atof(str);
2187 return 0;
2188}
2189
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002190static int trace__open_output(struct trace *trace, const char *filename)
2191{
2192 struct stat st;
2193
2194 if (!stat(filename, &st) && st.st_size) {
2195 char oldname[PATH_MAX];
2196
2197 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2198 unlink(oldname);
2199 rename(filename, oldname);
2200 }
2201
2202 trace->output = fopen(filename, "w");
2203
2204 return trace->output == NULL ? -errno : 0;
2205}
2206
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002207int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2208{
2209 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002210 "perf trace [<options>] [<command>]",
2211 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002212 "perf trace record [<options>] [<command>]",
2213 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002214 NULL
2215 };
2216 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002217 .audit = {
2218 .machine = audit_detect_machine(),
2219 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2220 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002221 .syscalls = {
2222 . max = -1,
2223 },
2224 .opts = {
2225 .target = {
2226 .uid = UINT_MAX,
2227 .uses_mmap = true,
2228 },
2229 .user_freq = UINT_MAX,
2230 .user_interval = ULLONG_MAX,
2231 .no_delay = true,
2232 .mmap_pages = 1024,
2233 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002234 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002235 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002236 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002237 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002238 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002239 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002240 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2241 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002242 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002243 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
2244 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002245 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002246 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002247 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2248 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002249 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002250 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002251 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002252 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002253 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002254 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002255 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002256 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002257 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2258 "number of mmap data pages",
2259 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002260 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002261 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002262 OPT_CALLBACK(0, "duration", &trace, "float",
2263 "show only events with duration > N.M ms",
2264 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002265 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002266 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002267 OPT_BOOLEAN('T', "time", &trace.full_time,
2268 "Show full timestamp, not time relative to first start"),
David Ahernbf2575c2013-10-08 21:26:53 -06002269 OPT_BOOLEAN(0, "summary", &trace.summary,
2270 "Show syscall summary with statistics"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002271 OPT_END()
2272 };
2273 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002274 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002275
David Ahern5e2485b2013-09-28 13:13:01 -06002276 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
2277 return trace__record(argc-2, &argv[2]);
2278
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002279 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002280
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002281 if (output_name != NULL) {
2282 err = trace__open_output(&trace, output_name);
2283 if (err < 0) {
2284 perror("failed to create output file");
2285 goto out;
2286 }
2287 }
2288
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002289 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002290 const char *s = ev_qualifier_str;
2291
2292 trace.not_ev_qualifier = *s == '!';
2293 if (trace.not_ev_qualifier)
2294 ++s;
2295 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002296 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002297 fputs("Not enough memory to parse event qualifier",
2298 trace.output);
2299 err = -ENOMEM;
2300 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002301 }
2302 }
2303
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002304 err = perf_target__validate(&trace.opts.target);
2305 if (err) {
2306 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002307 fprintf(trace.output, "%s", bf);
2308 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002309 }
2310
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002311 err = perf_target__parse_uid(&trace.opts.target);
2312 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002313 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002314 fprintf(trace.output, "%s", bf);
2315 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002316 }
2317
Namhyung Kimf15eb532012-10-05 14:02:16 +09002318 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002319 trace.opts.target.system_wide = true;
2320
David Ahern6810fc92013-08-28 22:29:52 -06002321 if (input_name)
2322 err = trace__replay(&trace);
2323 else
2324 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002325
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002326out_close:
2327 if (output_name != NULL)
2328 fclose(trace.output);
2329out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002330 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002331}