blob: c5b4bc51175cb63975af8cbb1ffc182f2a4f2e91 [file] [log] [blame]
Robert Richter4e319022013-06-11 17:29:18 +02001#include <traceevent/event-parse.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03003#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03004#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03005#include "util/evlist.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03006#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -06007#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03008#include "util/thread.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03009#include "util/parse-options.h"
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030010#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060011#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030012#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060013#include "util/stat.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010014#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070015#include "util/parse-events.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030016
17#include <libaudit.h>
18#include <stdlib.h>
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -030019#include <sys/eventfd.h>
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030020#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030021#include <linux/futex.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030022
Ingo Molnar456857b2013-09-12 15:29:00 +020023/* For older distros: */
24#ifndef MAP_STACK
25# define MAP_STACK 0x20000
26#endif
27
28#ifndef MADV_HWPOISON
29# define MADV_HWPOISON 100
30#endif
31
32#ifndef MADV_MERGEABLE
33# define MADV_MERGEABLE 12
34#endif
35
36#ifndef MADV_UNMERGEABLE
37# define MADV_UNMERGEABLE 13
38#endif
39
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -030040struct tp_field {
41 int offset;
42 union {
43 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
44 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
45 };
46};
47
48#define TP_UINT_FIELD(bits) \
49static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
50{ \
51 return *(u##bits *)(sample->raw_data + field->offset); \
52}
53
54TP_UINT_FIELD(8);
55TP_UINT_FIELD(16);
56TP_UINT_FIELD(32);
57TP_UINT_FIELD(64);
58
59#define TP_UINT_FIELD__SWAPPED(bits) \
60static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
61{ \
62 u##bits value = *(u##bits *)(sample->raw_data + field->offset); \
63 return bswap_##bits(value);\
64}
65
66TP_UINT_FIELD__SWAPPED(16);
67TP_UINT_FIELD__SWAPPED(32);
68TP_UINT_FIELD__SWAPPED(64);
69
70static int tp_field__init_uint(struct tp_field *field,
71 struct format_field *format_field,
72 bool needs_swap)
73{
74 field->offset = format_field->offset;
75
76 switch (format_field->size) {
77 case 1:
78 field->integer = tp_field__u8;
79 break;
80 case 2:
81 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
82 break;
83 case 4:
84 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
85 break;
86 case 8:
87 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
88 break;
89 default:
90 return -1;
91 }
92
93 return 0;
94}
95
96static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
97{
98 return sample->raw_data + field->offset;
99}
100
101static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
102{
103 field->offset = format_field->offset;
104 field->pointer = tp_field__ptr;
105 return 0;
106}
107
108struct syscall_tp {
109 struct tp_field id;
110 union {
111 struct tp_field args, ret;
112 };
113};
114
115static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
116 struct tp_field *field,
117 const char *name)
118{
119 struct format_field *format_field = perf_evsel__field(evsel, name);
120
121 if (format_field == NULL)
122 return -1;
123
124 return tp_field__init_uint(field, format_field, evsel->needs_swap);
125}
126
127#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
128 ({ struct syscall_tp *sc = evsel->priv;\
129 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
130
131static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
132 struct tp_field *field,
133 const char *name)
134{
135 struct format_field *format_field = perf_evsel__field(evsel, name);
136
137 if (format_field == NULL)
138 return -1;
139
140 return tp_field__init_ptr(field, format_field);
141}
142
143#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
144 ({ struct syscall_tp *sc = evsel->priv;\
145 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
146
147static void perf_evsel__delete_priv(struct perf_evsel *evsel)
148{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300149 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300150 perf_evsel__delete(evsel);
151}
152
Namhyung Kim96695d42013-11-12 08:51:45 -0300153static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
154{
155 evsel->priv = malloc(sizeof(struct syscall_tp));
156 if (evsel->priv != NULL) {
157 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
158 goto out_delete;
159
160 evsel->handler = handler;
161 return 0;
162 }
163
164 return -ENOMEM;
165
166out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300167 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300168 return -ENOENT;
169}
170
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300171static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300172{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300173 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300174
David Ahern9aca7f12013-12-04 19:41:39 -0700175 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
176 if (evsel == NULL)
177 evsel = perf_evsel__newtp("syscalls", direction);
178
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300179 if (evsel) {
Namhyung Kim96695d42013-11-12 08:51:45 -0300180 if (perf_evsel__init_syscall_tp(evsel, handler))
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300181 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300182 }
183
184 return evsel;
185
186out_delete:
187 perf_evsel__delete_priv(evsel);
188 return NULL;
189}
190
191#define perf_evsel__sc_tp_uint(evsel, name, sample) \
192 ({ struct syscall_tp *fields = evsel->priv; \
193 fields->name.integer(&fields->name, sample); })
194
195#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
196 ({ struct syscall_tp *fields = evsel->priv; \
197 fields->name.pointer(&fields->name, sample); })
198
199static int perf_evlist__add_syscall_newtp(struct perf_evlist *evlist,
200 void *sys_enter_handler,
201 void *sys_exit_handler)
202{
203 int ret = -1;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300204 struct perf_evsel *sys_enter, *sys_exit;
205
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300206 sys_enter = perf_evsel__syscall_newtp("sys_enter", sys_enter_handler);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300207 if (sys_enter == NULL)
208 goto out;
209
210 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
211 goto out_delete_sys_enter;
212
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300213 sys_exit = perf_evsel__syscall_newtp("sys_exit", sys_exit_handler);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300214 if (sys_exit == NULL)
215 goto out_delete_sys_enter;
216
217 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
218 goto out_delete_sys_exit;
219
220 perf_evlist__add(evlist, sys_enter);
221 perf_evlist__add(evlist, sys_exit);
222
223 ret = 0;
224out:
225 return ret;
226
227out_delete_sys_exit:
228 perf_evsel__delete_priv(sys_exit);
229out_delete_sys_enter:
230 perf_evsel__delete_priv(sys_enter);
231 goto out;
232}
233
234
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300235struct syscall_arg {
236 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300237 struct thread *thread;
238 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300239 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300240 u8 idx;
241 u8 mask;
242};
243
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300244struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300245 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300246 int nr_entries;
247 const char **entries;
248};
249
250#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
251 .nr_entries = ARRAY_SIZE(array), \
252 .entries = array, \
253}
254
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300255#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
256 .offset = off, \
257 .nr_entries = ARRAY_SIZE(array), \
258 .entries = array, \
259}
260
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300261static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
262 const char *intfmt,
263 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300264{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300265 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300266 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300267
268 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300269 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300270
271 return scnprintf(bf, size, "%s", sa->entries[idx]);
272}
273
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300274static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
275 struct syscall_arg *arg)
276{
277 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
278}
279
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300280#define SCA_STRARRAY syscall_arg__scnprintf_strarray
281
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300282static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
283 struct syscall_arg *arg)
284{
285 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
286}
287
288#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
289
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300290static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
291 struct syscall_arg *arg);
292
293#define SCA_FD syscall_arg__scnprintf_fd
294
295static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
296 struct syscall_arg *arg)
297{
298 int fd = arg->val;
299
300 if (fd == AT_FDCWD)
301 return scnprintf(bf, size, "CWD");
302
303 return syscall_arg__scnprintf_fd(bf, size, arg);
304}
305
306#define SCA_FDAT syscall_arg__scnprintf_fd_at
307
308static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
309 struct syscall_arg *arg);
310
311#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
312
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300313static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300314 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300315{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300316 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300317}
318
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300319#define SCA_HEX syscall_arg__scnprintf_hex
320
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300321static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300322 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300323{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300324 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300325
326 if (prot == PROT_NONE)
327 return scnprintf(bf, size, "NONE");
328#define P_MMAP_PROT(n) \
329 if (prot & PROT_##n) { \
330 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
331 prot &= ~PROT_##n; \
332 }
333
334 P_MMAP_PROT(EXEC);
335 P_MMAP_PROT(READ);
336 P_MMAP_PROT(WRITE);
337#ifdef PROT_SEM
338 P_MMAP_PROT(SEM);
339#endif
340 P_MMAP_PROT(GROWSDOWN);
341 P_MMAP_PROT(GROWSUP);
342#undef P_MMAP_PROT
343
344 if (prot)
345 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
346
347 return printed;
348}
349
350#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
351
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300352static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300353 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300354{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300355 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300356
357#define P_MMAP_FLAG(n) \
358 if (flags & MAP_##n) { \
359 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
360 flags &= ~MAP_##n; \
361 }
362
363 P_MMAP_FLAG(SHARED);
364 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400365#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300366 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400367#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300368 P_MMAP_FLAG(ANONYMOUS);
369 P_MMAP_FLAG(DENYWRITE);
370 P_MMAP_FLAG(EXECUTABLE);
371 P_MMAP_FLAG(FILE);
372 P_MMAP_FLAG(FIXED);
373 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600374#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300375 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600376#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300377 P_MMAP_FLAG(LOCKED);
378 P_MMAP_FLAG(NONBLOCK);
379 P_MMAP_FLAG(NORESERVE);
380 P_MMAP_FLAG(POPULATE);
381 P_MMAP_FLAG(STACK);
382#ifdef MAP_UNINITIALIZED
383 P_MMAP_FLAG(UNINITIALIZED);
384#endif
385#undef P_MMAP_FLAG
386
387 if (flags)
388 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
389
390 return printed;
391}
392
393#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
394
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300395static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300396 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300397{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300398 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300399
400 switch (behavior) {
401#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
402 P_MADV_BHV(NORMAL);
403 P_MADV_BHV(RANDOM);
404 P_MADV_BHV(SEQUENTIAL);
405 P_MADV_BHV(WILLNEED);
406 P_MADV_BHV(DONTNEED);
407 P_MADV_BHV(REMOVE);
408 P_MADV_BHV(DONTFORK);
409 P_MADV_BHV(DOFORK);
410 P_MADV_BHV(HWPOISON);
411#ifdef MADV_SOFT_OFFLINE
412 P_MADV_BHV(SOFT_OFFLINE);
413#endif
414 P_MADV_BHV(MERGEABLE);
415 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600416#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300417 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600418#endif
419#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300420 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600421#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300422#ifdef MADV_DONTDUMP
423 P_MADV_BHV(DONTDUMP);
424#endif
425#ifdef MADV_DODUMP
426 P_MADV_BHV(DODUMP);
427#endif
428#undef P_MADV_PHV
429 default: break;
430 }
431
432 return scnprintf(bf, size, "%#x", behavior);
433}
434
435#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
436
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300437static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
438 struct syscall_arg *arg)
439{
440 int printed = 0, op = arg->val;
441
442 if (op == 0)
443 return scnprintf(bf, size, "NONE");
444#define P_CMD(cmd) \
445 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
446 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
447 op &= ~LOCK_##cmd; \
448 }
449
450 P_CMD(SH);
451 P_CMD(EX);
452 P_CMD(NB);
453 P_CMD(UN);
454 P_CMD(MAND);
455 P_CMD(RW);
456 P_CMD(READ);
457 P_CMD(WRITE);
458#undef P_OP
459
460 if (op)
461 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
462
463 return printed;
464}
465
466#define SCA_FLOCK syscall_arg__scnprintf_flock
467
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300468static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300469{
470 enum syscall_futex_args {
471 SCF_UADDR = (1 << 0),
472 SCF_OP = (1 << 1),
473 SCF_VAL = (1 << 2),
474 SCF_TIMEOUT = (1 << 3),
475 SCF_UADDR2 = (1 << 4),
476 SCF_VAL3 = (1 << 5),
477 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300478 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300479 int cmd = op & FUTEX_CMD_MASK;
480 size_t printed = 0;
481
482 switch (cmd) {
483#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300484 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
485 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
486 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
487 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
488 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
489 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300490 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300491 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
492 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
493 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
494 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
495 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300496 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
497 default: printed = scnprintf(bf, size, "%#x", cmd); break;
498 }
499
500 if (op & FUTEX_PRIVATE_FLAG)
501 printed += scnprintf(bf + printed, size - printed, "|PRIV");
502
503 if (op & FUTEX_CLOCK_REALTIME)
504 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
505
506 return printed;
507}
508
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300509#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
510
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300511static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
512static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300513
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300514static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
515static DEFINE_STRARRAY(itimers);
516
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300517static const char *whences[] = { "SET", "CUR", "END",
518#ifdef SEEK_DATA
519"DATA",
520#endif
521#ifdef SEEK_HOLE
522"HOLE",
523#endif
524};
525static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300526
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300527static const char *fcntl_cmds[] = {
528 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
529 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
530 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
531 "F_GETOWNER_UIDS",
532};
533static DEFINE_STRARRAY(fcntl_cmds);
534
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300535static const char *rlimit_resources[] = {
536 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
537 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
538 "RTTIME",
539};
540static DEFINE_STRARRAY(rlimit_resources);
541
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300542static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
543static DEFINE_STRARRAY(sighow);
544
David Ahern4f8c1b72013-09-22 19:45:00 -0600545static const char *clockid[] = {
546 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
547 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
548};
549static DEFINE_STRARRAY(clockid);
550
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300551static const char *socket_families[] = {
552 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
553 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
554 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
555 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
556 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
557 "ALG", "NFC", "VSOCK",
558};
559static DEFINE_STRARRAY(socket_families);
560
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300561#ifndef SOCK_TYPE_MASK
562#define SOCK_TYPE_MASK 0xf
563#endif
564
565static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
566 struct syscall_arg *arg)
567{
568 size_t printed;
569 int type = arg->val,
570 flags = type & ~SOCK_TYPE_MASK;
571
572 type &= SOCK_TYPE_MASK;
573 /*
574 * Can't use a strarray, MIPS may override for ABI reasons.
575 */
576 switch (type) {
577#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
578 P_SK_TYPE(STREAM);
579 P_SK_TYPE(DGRAM);
580 P_SK_TYPE(RAW);
581 P_SK_TYPE(RDM);
582 P_SK_TYPE(SEQPACKET);
583 P_SK_TYPE(DCCP);
584 P_SK_TYPE(PACKET);
585#undef P_SK_TYPE
586 default:
587 printed = scnprintf(bf, size, "%#x", type);
588 }
589
590#define P_SK_FLAG(n) \
591 if (flags & SOCK_##n) { \
592 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
593 flags &= ~SOCK_##n; \
594 }
595
596 P_SK_FLAG(CLOEXEC);
597 P_SK_FLAG(NONBLOCK);
598#undef P_SK_FLAG
599
600 if (flags)
601 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
602
603 return printed;
604}
605
606#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
607
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300608#ifndef MSG_PROBE
609#define MSG_PROBE 0x10
610#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600611#ifndef MSG_WAITFORONE
612#define MSG_WAITFORONE 0x10000
613#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300614#ifndef MSG_SENDPAGE_NOTLAST
615#define MSG_SENDPAGE_NOTLAST 0x20000
616#endif
617#ifndef MSG_FASTOPEN
618#define MSG_FASTOPEN 0x20000000
619#endif
620
621static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
622 struct syscall_arg *arg)
623{
624 int printed = 0, flags = arg->val;
625
626 if (flags == 0)
627 return scnprintf(bf, size, "NONE");
628#define P_MSG_FLAG(n) \
629 if (flags & MSG_##n) { \
630 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
631 flags &= ~MSG_##n; \
632 }
633
634 P_MSG_FLAG(OOB);
635 P_MSG_FLAG(PEEK);
636 P_MSG_FLAG(DONTROUTE);
637 P_MSG_FLAG(TRYHARD);
638 P_MSG_FLAG(CTRUNC);
639 P_MSG_FLAG(PROBE);
640 P_MSG_FLAG(TRUNC);
641 P_MSG_FLAG(DONTWAIT);
642 P_MSG_FLAG(EOR);
643 P_MSG_FLAG(WAITALL);
644 P_MSG_FLAG(FIN);
645 P_MSG_FLAG(SYN);
646 P_MSG_FLAG(CONFIRM);
647 P_MSG_FLAG(RST);
648 P_MSG_FLAG(ERRQUEUE);
649 P_MSG_FLAG(NOSIGNAL);
650 P_MSG_FLAG(MORE);
651 P_MSG_FLAG(WAITFORONE);
652 P_MSG_FLAG(SENDPAGE_NOTLAST);
653 P_MSG_FLAG(FASTOPEN);
654 P_MSG_FLAG(CMSG_CLOEXEC);
655#undef P_MSG_FLAG
656
657 if (flags)
658 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
659
660 return printed;
661}
662
663#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
664
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300665static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
666 struct syscall_arg *arg)
667{
668 size_t printed = 0;
669 int mode = arg->val;
670
671 if (mode == F_OK) /* 0 */
672 return scnprintf(bf, size, "F");
673#define P_MODE(n) \
674 if (mode & n##_OK) { \
675 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
676 mode &= ~n##_OK; \
677 }
678
679 P_MODE(R);
680 P_MODE(W);
681 P_MODE(X);
682#undef P_MODE
683
684 if (mode)
685 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
686
687 return printed;
688}
689
690#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
691
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300692static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300693 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300694{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300695 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300696
697 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300698 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300699
700 if (flags == 0)
701 return scnprintf(bf, size, "RDONLY");
702#define P_FLAG(n) \
703 if (flags & O_##n) { \
704 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
705 flags &= ~O_##n; \
706 }
707
708 P_FLAG(APPEND);
709 P_FLAG(ASYNC);
710 P_FLAG(CLOEXEC);
711 P_FLAG(CREAT);
712 P_FLAG(DIRECT);
713 P_FLAG(DIRECTORY);
714 P_FLAG(EXCL);
715 P_FLAG(LARGEFILE);
716 P_FLAG(NOATIME);
717 P_FLAG(NOCTTY);
718#ifdef O_NONBLOCK
719 P_FLAG(NONBLOCK);
720#elif O_NDELAY
721 P_FLAG(NDELAY);
722#endif
723#ifdef O_PATH
724 P_FLAG(PATH);
725#endif
726 P_FLAG(RDWR);
727#ifdef O_DSYNC
728 if ((flags & O_SYNC) == O_SYNC)
729 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
730 else {
731 P_FLAG(DSYNC);
732 }
733#else
734 P_FLAG(SYNC);
735#endif
736 P_FLAG(TRUNC);
737 P_FLAG(WRONLY);
738#undef P_FLAG
739
740 if (flags)
741 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
742
743 return printed;
744}
745
746#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
747
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300748static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
749 struct syscall_arg *arg)
750{
751 int printed = 0, flags = arg->val;
752
753 if (flags == 0)
754 return scnprintf(bf, size, "NONE");
755#define P_FLAG(n) \
756 if (flags & EFD_##n) { \
757 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
758 flags &= ~EFD_##n; \
759 }
760
761 P_FLAG(SEMAPHORE);
762 P_FLAG(CLOEXEC);
763 P_FLAG(NONBLOCK);
764#undef P_FLAG
765
766 if (flags)
767 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
768
769 return printed;
770}
771
772#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
773
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300774static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
775 struct syscall_arg *arg)
776{
777 int printed = 0, flags = arg->val;
778
779#define P_FLAG(n) \
780 if (flags & O_##n) { \
781 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
782 flags &= ~O_##n; \
783 }
784
785 P_FLAG(CLOEXEC);
786 P_FLAG(NONBLOCK);
787#undef P_FLAG
788
789 if (flags)
790 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
791
792 return printed;
793}
794
795#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
796
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300797static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
798{
799 int sig = arg->val;
800
801 switch (sig) {
802#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
803 P_SIGNUM(HUP);
804 P_SIGNUM(INT);
805 P_SIGNUM(QUIT);
806 P_SIGNUM(ILL);
807 P_SIGNUM(TRAP);
808 P_SIGNUM(ABRT);
809 P_SIGNUM(BUS);
810 P_SIGNUM(FPE);
811 P_SIGNUM(KILL);
812 P_SIGNUM(USR1);
813 P_SIGNUM(SEGV);
814 P_SIGNUM(USR2);
815 P_SIGNUM(PIPE);
816 P_SIGNUM(ALRM);
817 P_SIGNUM(TERM);
818 P_SIGNUM(STKFLT);
819 P_SIGNUM(CHLD);
820 P_SIGNUM(CONT);
821 P_SIGNUM(STOP);
822 P_SIGNUM(TSTP);
823 P_SIGNUM(TTIN);
824 P_SIGNUM(TTOU);
825 P_SIGNUM(URG);
826 P_SIGNUM(XCPU);
827 P_SIGNUM(XFSZ);
828 P_SIGNUM(VTALRM);
829 P_SIGNUM(PROF);
830 P_SIGNUM(WINCH);
831 P_SIGNUM(IO);
832 P_SIGNUM(PWR);
833 P_SIGNUM(SYS);
834 default: break;
835 }
836
837 return scnprintf(bf, size, "%#x", sig);
838}
839
840#define SCA_SIGNUM syscall_arg__scnprintf_signum
841
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300842#define TCGETS 0x5401
843
844static const char *tioctls[] = {
845 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
846 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
847 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
848 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
849 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
850 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
851 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
852 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
853 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
854 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
855 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
856 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
857 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
858 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
859 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
860};
861
862static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
863
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300864#define STRARRAY(arg, name, array) \
865 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
866 .arg_parm = { [arg] = &strarray__##array, }
867
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300868static struct syscall_fmt {
869 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300870 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300871 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300872 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300873 bool errmsg;
874 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300875 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300876} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300877 { .name = "access", .errmsg = true,
878 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300879 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300880 { .name = "brk", .hexret = true,
881 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600882 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300883 { .name = "close", .errmsg = true,
884 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300885 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300886 { .name = "dup", .errmsg = true,
887 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
888 { .name = "dup2", .errmsg = true,
889 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
890 { .name = "dup3", .errmsg = true,
891 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300892 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300893 { .name = "eventfd2", .errmsg = true,
894 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300895 { .name = "faccessat", .errmsg = true,
896 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
897 { .name = "fadvise64", .errmsg = true,
898 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
899 { .name = "fallocate", .errmsg = true,
900 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
901 { .name = "fchdir", .errmsg = true,
902 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
903 { .name = "fchmod", .errmsg = true,
904 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
905 { .name = "fchmodat", .errmsg = true,
906 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
907 { .name = "fchown", .errmsg = true,
908 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
909 { .name = "fchownat", .errmsg = true,
910 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
911 { .name = "fcntl", .errmsg = true,
912 .arg_scnprintf = { [0] = SCA_FD, /* fd */
913 [1] = SCA_STRARRAY, /* cmd */ },
914 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
915 { .name = "fdatasync", .errmsg = true,
916 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300917 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300918 .arg_scnprintf = { [0] = SCA_FD, /* fd */
919 [1] = SCA_FLOCK, /* cmd */ }, },
920 { .name = "fsetxattr", .errmsg = true,
921 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
922 { .name = "fstat", .errmsg = true, .alias = "newfstat",
923 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
924 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
925 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
926 { .name = "fstatfs", .errmsg = true,
927 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
928 { .name = "fsync", .errmsg = true,
929 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
930 { .name = "ftruncate", .errmsg = true,
931 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300932 { .name = "futex", .errmsg = true,
933 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300934 { .name = "futimesat", .errmsg = true,
935 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
936 { .name = "getdents", .errmsg = true,
937 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
938 { .name = "getdents64", .errmsg = true,
939 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300940 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
941 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300942 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300943 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300944 [1] = SCA_STRHEXARRAY, /* cmd */
945 [2] = SCA_HEX, /* arg */ },
946 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300947 { .name = "kill", .errmsg = true,
948 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300949 { .name = "linkat", .errmsg = true,
950 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
951 { .name = "lseek", .errmsg = true,
952 .arg_scnprintf = { [0] = SCA_FD, /* fd */
953 [2] = SCA_STRARRAY, /* whence */ },
954 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300955 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300956 { .name = "madvise", .errmsg = true,
957 .arg_scnprintf = { [0] = SCA_HEX, /* start */
958 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300959 { .name = "mkdirat", .errmsg = true,
960 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
961 { .name = "mknodat", .errmsg = true,
962 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300963 { .name = "mlock", .errmsg = true,
964 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
965 { .name = "mlockall", .errmsg = true,
966 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300967 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300968 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300969 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +0900970 [3] = SCA_MMAP_FLAGS, /* flags */
971 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300972 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300973 .arg_scnprintf = { [0] = SCA_HEX, /* start */
974 [2] = SCA_MMAP_PROT, /* prot */ }, },
975 { .name = "mremap", .hexret = true,
976 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
977 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300978 { .name = "munlock", .errmsg = true,
979 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300980 { .name = "munmap", .errmsg = true,
981 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300982 { .name = "name_to_handle_at", .errmsg = true,
983 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
984 { .name = "newfstatat", .errmsg = true,
985 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300986 { .name = "open", .errmsg = true,
987 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300988 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300989 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
990 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300991 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300992 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
993 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300994 { .name = "pipe2", .errmsg = true,
995 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300996 { .name = "poll", .errmsg = true, .timeout = true, },
997 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300998 { .name = "pread", .errmsg = true, .alias = "pread64",
999 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1000 { .name = "preadv", .errmsg = true, .alias = "pread",
1001 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001002 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001003 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
1004 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1005 { .name = "pwritev", .errmsg = true,
1006 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1007 { .name = "read", .errmsg = true,
1008 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1009 { .name = "readlinkat", .errmsg = true,
1010 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1011 { .name = "readv", .errmsg = true,
1012 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001013 { .name = "recvfrom", .errmsg = true,
1014 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1015 { .name = "recvmmsg", .errmsg = true,
1016 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1017 { .name = "recvmsg", .errmsg = true,
1018 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001019 { .name = "renameat", .errmsg = true,
1020 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001021 { .name = "rt_sigaction", .errmsg = true,
1022 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001023 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001024 { .name = "rt_sigqueueinfo", .errmsg = true,
1025 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1026 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1027 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001028 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001029 { .name = "sendmmsg", .errmsg = true,
1030 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1031 { .name = "sendmsg", .errmsg = true,
1032 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
1033 { .name = "sendto", .errmsg = true,
1034 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001035 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1036 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001037 { .name = "shutdown", .errmsg = true,
1038 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001039 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001040 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1041 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001042 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001043 { .name = "socketpair", .errmsg = true,
1044 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1045 [1] = SCA_SK_TYPE, /* type */ },
1046 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001047 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001048 { .name = "symlinkat", .errmsg = true,
1049 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001050 { .name = "tgkill", .errmsg = true,
1051 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1052 { .name = "tkill", .errmsg = true,
1053 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001054 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001055 { .name = "unlinkat", .errmsg = true,
1056 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1057 { .name = "utimensat", .errmsg = true,
1058 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
1059 { .name = "write", .errmsg = true,
1060 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1061 { .name = "writev", .errmsg = true,
1062 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001063};
1064
1065static int syscall_fmt__cmp(const void *name, const void *fmtp)
1066{
1067 const struct syscall_fmt *fmt = fmtp;
1068 return strcmp(name, fmt->name);
1069}
1070
1071static struct syscall_fmt *syscall_fmt__find(const char *name)
1072{
1073 const int nmemb = ARRAY_SIZE(syscall_fmts);
1074 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1075}
1076
1077struct syscall {
1078 struct event_format *tp_format;
1079 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001080 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001081 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001082 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001083 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001084};
1085
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001086static size_t fprintf_duration(unsigned long t, FILE *fp)
1087{
1088 double duration = (double)t / NSEC_PER_MSEC;
1089 size_t printed = fprintf(fp, "(");
1090
1091 if (duration >= 1.0)
1092 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1093 else if (duration >= 0.01)
1094 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1095 else
1096 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001097 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001098}
1099
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001100struct thread_trace {
1101 u64 entry_time;
1102 u64 exit_time;
1103 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001104 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001105 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001106 double runtime_ms;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001107 struct {
1108 int max;
1109 char **table;
1110 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001111
1112 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001113};
1114
1115static struct thread_trace *thread_trace__new(void)
1116{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001117 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1118
1119 if (ttrace)
1120 ttrace->paths.max = -1;
1121
David Ahernbf2575c2013-10-08 21:26:53 -06001122 ttrace->syscall_stats = intlist__new(NULL);
1123
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001124 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001125}
1126
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001127static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001128{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001129 struct thread_trace *ttrace;
1130
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001131 if (thread == NULL)
1132 goto fail;
1133
1134 if (thread->priv == NULL)
1135 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001136
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001137 if (thread->priv == NULL)
1138 goto fail;
1139
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001140 ttrace = thread->priv;
1141 ++ttrace->nr_events;
1142
1143 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001144fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001145 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001146 "WARNING: not enough memory, dropping samples!\n");
1147 return NULL;
1148}
1149
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001150struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001151 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001152 struct {
1153 int machine;
1154 int open_id;
1155 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001156 struct {
1157 int max;
1158 struct syscall *table;
1159 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001160 struct record_opts opts;
David Ahern8fb598e2013-09-28 13:13:00 -06001161 struct machine *host;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001162 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -06001163 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001164 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001165 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001166 struct strlist *ev_qualifier;
1167 bool not_ev_qualifier;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001168 bool live;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001169 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -06001170 struct intlist *tid_list;
1171 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001172 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001173 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001174 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001175 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001176 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001177 bool show_tool_stats;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001178 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001179 double runtime_ms;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001180 struct {
1181 u64 vfs_getname, proc_getname;
1182 } stats;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001183};
1184
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001185static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001186{
1187 struct thread_trace *ttrace = thread->priv;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001188
1189 if (fd > ttrace->paths.max) {
1190 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1191
1192 if (npath == NULL)
1193 return -1;
1194
1195 if (ttrace->paths.max != -1) {
1196 memset(npath + ttrace->paths.max + 1, 0,
1197 (fd - ttrace->paths.max) * sizeof(char *));
1198 } else {
1199 memset(npath, 0, (fd + 1) * sizeof(char *));
1200 }
1201
1202 ttrace->paths.table = npath;
1203 ttrace->paths.max = fd;
1204 }
1205
1206 ttrace->paths.table[fd] = strdup(pathname);
1207
1208 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1209}
1210
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001211static int thread__read_fd_path(struct thread *thread, int fd)
1212{
1213 char linkname[PATH_MAX], pathname[PATH_MAX];
1214 struct stat st;
1215 int ret;
1216
1217 if (thread->pid_ == thread->tid) {
1218 scnprintf(linkname, sizeof(linkname),
1219 "/proc/%d/fd/%d", thread->pid_, fd);
1220 } else {
1221 scnprintf(linkname, sizeof(linkname),
1222 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1223 }
1224
1225 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1226 return -1;
1227
1228 ret = readlink(linkname, pathname, sizeof(pathname));
1229
1230 if (ret < 0 || ret > st.st_size)
1231 return -1;
1232
1233 pathname[ret] = '\0';
1234 return trace__set_fd_pathname(thread, fd, pathname);
1235}
1236
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001237static const char *thread__fd_path(struct thread *thread, int fd,
1238 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001239{
1240 struct thread_trace *ttrace = thread->priv;
1241
1242 if (ttrace == NULL)
1243 return NULL;
1244
1245 if (fd < 0)
1246 return NULL;
1247
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001248 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL))
1249 if (!trace->live)
1250 return NULL;
1251 ++trace->stats.proc_getname;
1252 if (thread__read_fd_path(thread, fd)) {
1253 return NULL;
1254 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001255
1256 return ttrace->paths.table[fd];
1257}
1258
1259static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1260 struct syscall_arg *arg)
1261{
1262 int fd = arg->val;
1263 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001264 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001265
1266 if (path)
1267 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1268
1269 return printed;
1270}
1271
1272static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1273 struct syscall_arg *arg)
1274{
1275 int fd = arg->val;
1276 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1277 struct thread_trace *ttrace = arg->thread->priv;
1278
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001279 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1280 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001281
1282 return printed;
1283}
1284
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001285static bool trace__filter_duration(struct trace *trace, double t)
1286{
1287 return t < (trace->duration_filter * NSEC_PER_MSEC);
1288}
1289
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001290static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1291{
1292 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1293
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001294 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001295}
1296
Namhyung Kimf15eb532012-10-05 14:02:16 +09001297static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001298static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001299
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001300static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001301{
1302 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001303 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001304}
1305
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001306static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001307 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001308{
1309 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001310 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001311
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001312 if (trace->multiple_threads) {
1313 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001314 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001315 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001316 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001317
1318 return printed;
1319}
1320
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001321static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001322 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001323{
1324 int ret = 0;
1325
1326 switch (event->header.type) {
1327 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001328 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001329 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001330 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001331 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001332 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001333 break;
1334 }
1335
1336 return ret;
1337}
1338
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001339static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001340 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001341 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001342 struct machine *machine)
1343{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001344 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001345 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001346}
1347
1348static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1349{
1350 int err = symbol__init();
1351
1352 if (err)
1353 return err;
1354
David Ahern8fb598e2013-09-28 13:13:00 -06001355 trace->host = machine__new_host();
1356 if (trace->host == NULL)
1357 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001358
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001359 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
1360 evlist->threads, trace__tool_process, false);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001361 if (err)
1362 symbol__exit();
1363
1364 return err;
1365}
1366
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001367static int syscall__set_arg_fmts(struct syscall *sc)
1368{
1369 struct format_field *field;
1370 int idx = 0;
1371
1372 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1373 if (sc->arg_scnprintf == NULL)
1374 return -1;
1375
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001376 if (sc->fmt)
1377 sc->arg_parm = sc->fmt->arg_parm;
1378
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001379 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001380 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1381 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1382 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001383 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1384 ++idx;
1385 }
1386
1387 return 0;
1388}
1389
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001390static int trace__read_syscall_info(struct trace *trace, int id)
1391{
1392 char tp_name[128];
1393 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001394 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001395
1396 if (name == NULL)
1397 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001398
1399 if (id > trace->syscalls.max) {
1400 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1401
1402 if (nsyscalls == NULL)
1403 return -1;
1404
1405 if (trace->syscalls.max != -1) {
1406 memset(nsyscalls + trace->syscalls.max + 1, 0,
1407 (id - trace->syscalls.max) * sizeof(*sc));
1408 } else {
1409 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1410 }
1411
1412 trace->syscalls.table = nsyscalls;
1413 trace->syscalls.max = id;
1414 }
1415
1416 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001417 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001418
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001419 if (trace->ev_qualifier) {
1420 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1421
1422 if (!(in ^ trace->not_ev_qualifier)) {
1423 sc->filtered = true;
1424 /*
1425 * No need to do read tracepoint information since this will be
1426 * filtered out.
1427 */
1428 return 0;
1429 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001430 }
1431
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001432 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001433
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001434 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001435 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001436
1437 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1438 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001439 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001440 }
1441
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001442 if (sc->tp_format == NULL)
1443 return -1;
1444
1445 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001446}
1447
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001448static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001449 unsigned long *args, struct trace *trace,
1450 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001451{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001452 size_t printed = 0;
1453
1454 if (sc->tp_format != NULL) {
1455 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001456 u8 bit = 1;
1457 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001458 .idx = 0,
1459 .mask = 0,
1460 .trace = trace,
1461 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001462 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001463
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001464 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001465 field = field->next, ++arg.idx, bit <<= 1) {
1466 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001467 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001468 /*
1469 * Suppress this argument if its value is zero and
1470 * and we don't have a string associated in an
1471 * strarray for it.
1472 */
1473 if (args[arg.idx] == 0 &&
1474 !(sc->arg_scnprintf &&
1475 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1476 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001477 continue;
1478
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001479 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001480 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001481 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1482 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001483 if (sc->arg_parm)
1484 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001485 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1486 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001487 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001488 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001489 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001490 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001491 }
1492 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001493 int i = 0;
1494
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001495 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001496 printed += scnprintf(bf + printed, size - printed,
1497 "%sarg%d: %ld",
1498 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001499 ++i;
1500 }
1501 }
1502
1503 return printed;
1504}
1505
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001506typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1507 struct perf_sample *sample);
1508
1509static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001510 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001511{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001512
1513 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001514
1515 /*
1516 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1517 * before that, leaving at a higher verbosity level till that is
1518 * explained. Reproduced with plain ftrace with:
1519 *
1520 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1521 * grep "NR -1 " /t/trace_pipe
1522 *
1523 * After generating some load on the machine.
1524 */
1525 if (verbose > 1) {
1526 static u64 n;
1527 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1528 id, perf_evsel__name(evsel), ++n);
1529 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001530 return NULL;
1531 }
1532
1533 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1534 trace__read_syscall_info(trace, id))
1535 goto out_cant_read;
1536
1537 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1538 goto out_cant_read;
1539
1540 return &trace->syscalls.table[id];
1541
1542out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001543 if (verbose) {
1544 fprintf(trace->output, "Problems reading syscall %d", id);
1545 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1546 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1547 fputs(" information\n", trace->output);
1548 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001549 return NULL;
1550}
1551
David Ahernbf2575c2013-10-08 21:26:53 -06001552static void thread__update_stats(struct thread_trace *ttrace,
1553 int id, struct perf_sample *sample)
1554{
1555 struct int_node *inode;
1556 struct stats *stats;
1557 u64 duration = 0;
1558
1559 inode = intlist__findnew(ttrace->syscall_stats, id);
1560 if (inode == NULL)
1561 return;
1562
1563 stats = inode->priv;
1564 if (stats == NULL) {
1565 stats = malloc(sizeof(struct stats));
1566 if (stats == NULL)
1567 return;
1568 init_stats(stats);
1569 inode->priv = stats;
1570 }
1571
1572 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1573 duration = sample->time - ttrace->entry_time;
1574
1575 update_stats(stats, duration);
1576}
1577
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001578static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1579 struct perf_sample *sample)
1580{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001581 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001582 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001583 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001584 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001585 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001586 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001587 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001588
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001589 if (sc == NULL)
1590 return -1;
1591
1592 if (sc->filtered)
1593 return 0;
1594
David Ahern8fb598e2013-09-28 13:13:00 -06001595 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001596 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001597 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001598 return -1;
1599
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001600 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001601 ttrace = thread->priv;
1602
1603 if (ttrace->entry_str == NULL) {
1604 ttrace->entry_str = malloc(1024);
1605 if (!ttrace->entry_str)
1606 return -1;
1607 }
1608
1609 ttrace->entry_time = sample->time;
1610 msg = ttrace->entry_str;
1611 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1612
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001613 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1614 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001615
1616 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001617 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001618 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1619 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001620 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001621 } else
1622 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001623
1624 return 0;
1625}
1626
1627static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1628 struct perf_sample *sample)
1629{
1630 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001631 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001632 struct thread *thread;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001633 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
David Ahernbf2575c2013-10-08 21:26:53 -06001634 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001635 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001636
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001637 if (sc == NULL)
1638 return -1;
1639
1640 if (sc->filtered)
1641 return 0;
1642
David Ahern8fb598e2013-09-28 13:13:00 -06001643 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001644 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001645 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001646 return -1;
1647
David Ahernbf2575c2013-10-08 21:26:53 -06001648 if (trace->summary)
1649 thread__update_stats(ttrace, id, sample);
1650
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001651 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001652
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001653 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1654 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1655 trace->last_vfs_getname = NULL;
1656 ++trace->stats.vfs_getname;
1657 }
1658
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001659 ttrace = thread->priv;
1660
1661 ttrace->exit_time = sample->time;
1662
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001663 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001664 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001665 if (trace__filter_duration(trace, duration))
1666 goto out;
1667 } else if (trace->duration_filter)
1668 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001669
David Ahernfd2eaba2013-11-12 09:31:15 -07001670 if (trace->summary_only)
1671 goto out;
1672
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001673 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001674
1675 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001676 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001677 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001678 fprintf(trace->output, " ... [");
1679 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1680 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001681 }
1682
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001683 if (sc->fmt == NULL) {
1684signed_print:
1685 fprintf(trace->output, ") = %d", ret);
1686 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001687 char bf[256];
1688 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1689 *e = audit_errno_to_name(-ret);
1690
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001691 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001692 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001693 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001694 else if (sc->fmt->hexret)
1695 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001696 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001697 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001698
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001699 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001700out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001701 ttrace->entry_pending = false;
1702
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001703 return 0;
1704}
1705
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001706static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1707 struct perf_sample *sample)
1708{
1709 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1710 return 0;
1711}
1712
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001713static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1714 struct perf_sample *sample)
1715{
1716 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1717 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001718 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001719 sample->pid,
1720 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001721 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001722
1723 if (ttrace == NULL)
1724 goto out_dump;
1725
1726 ttrace->runtime_ms += runtime_ms;
1727 trace->runtime_ms += runtime_ms;
1728 return 0;
1729
1730out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001731 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001732 evsel->name,
1733 perf_evsel__strval(evsel, sample, "comm"),
1734 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1735 runtime,
1736 perf_evsel__intval(evsel, sample, "vruntime"));
1737 return 0;
1738}
1739
David Ahernbdc89662013-08-28 22:29:53 -06001740static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1741{
1742 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1743 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1744 return false;
1745
1746 if (trace->pid_list || trace->tid_list)
1747 return true;
1748
1749 return false;
1750}
1751
David Ahern6810fc92013-08-28 22:29:52 -06001752static int trace__process_sample(struct perf_tool *tool,
1753 union perf_event *event __maybe_unused,
1754 struct perf_sample *sample,
1755 struct perf_evsel *evsel,
1756 struct machine *machine __maybe_unused)
1757{
1758 struct trace *trace = container_of(tool, struct trace, tool);
1759 int err = 0;
1760
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001761 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001762
David Ahernbdc89662013-08-28 22:29:53 -06001763 if (skip_sample(trace, sample))
1764 return 0;
1765
David Ahern4bb09192013-09-04 12:37:43 -06001766 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001767 trace->base_time = sample->time;
1768
David Ahern31605652013-12-04 19:41:41 -07001769 if (handler) {
1770 ++trace->nr_events;
David Ahern6810fc92013-08-28 22:29:52 -06001771 handler(trace, evsel, sample);
David Ahern31605652013-12-04 19:41:41 -07001772 }
David Ahern6810fc92013-08-28 22:29:52 -06001773
1774 return err;
1775}
1776
David Ahernbdc89662013-08-28 22:29:53 -06001777static int parse_target_str(struct trace *trace)
1778{
1779 if (trace->opts.target.pid) {
1780 trace->pid_list = intlist__new(trace->opts.target.pid);
1781 if (trace->pid_list == NULL) {
1782 pr_err("Error parsing process id string\n");
1783 return -EINVAL;
1784 }
1785 }
1786
1787 if (trace->opts.target.tid) {
1788 trace->tid_list = intlist__new(trace->opts.target.tid);
1789 if (trace->tid_list == NULL) {
1790 pr_err("Error parsing thread id string\n");
1791 return -EINVAL;
1792 }
1793 }
1794
1795 return 0;
1796}
1797
David Ahern5e2485b2013-09-28 13:13:01 -06001798static int trace__record(int argc, const char **argv)
1799{
1800 unsigned int rec_argc, i, j;
1801 const char **rec_argv;
1802 const char * const record_args[] = {
1803 "record",
1804 "-R",
1805 "-m", "1024",
1806 "-c", "1",
David Ahern9aca7f12013-12-04 19:41:39 -07001807 "-e",
David Ahern5e2485b2013-09-28 13:13:01 -06001808 };
1809
David Ahern9aca7f12013-12-04 19:41:39 -07001810 /* +1 is for the event string below */
1811 rec_argc = ARRAY_SIZE(record_args) + 1 + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06001812 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1813
1814 if (rec_argv == NULL)
1815 return -ENOMEM;
1816
1817 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1818 rec_argv[i] = record_args[i];
1819
David Ahern9aca7f12013-12-04 19:41:39 -07001820 /* event string may be different for older kernels - e.g., RHEL6 */
1821 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
1822 rec_argv[i] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
1823 else if (is_valid_tracepoint("syscalls:sys_enter"))
1824 rec_argv[i] = "syscalls:sys_enter,syscalls:sys_exit";
1825 else {
1826 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
1827 return -1;
1828 }
1829 i++;
1830
David Ahern5e2485b2013-09-28 13:13:01 -06001831 for (j = 0; j < (unsigned int)argc; j++, i++)
1832 rec_argv[i] = argv[j];
1833
1834 return cmd_record(i, rec_argv, NULL);
1835}
1836
David Ahernbf2575c2013-10-08 21:26:53 -06001837static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
1838
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001839static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
1840{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03001841 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001842 if (evsel == NULL)
1843 return;
1844
1845 if (perf_evsel__field(evsel, "pathname") == NULL) {
1846 perf_evsel__delete(evsel);
1847 return;
1848 }
1849
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001850 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001851 perf_evlist__add(evlist, evsel);
1852}
1853
Namhyung Kimf15eb532012-10-05 14:02:16 +09001854static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001855{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001856 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001857 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001858 int err = -1, i;
1859 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001860 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001861
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001862 trace->live = true;
1863
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001864 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001865 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001866 goto out;
1867 }
1868
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001869 if (perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, trace__sys_exit))
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301870 goto out_error_tp;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001871
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001872 perf_evlist__add_vfs_getname(evlist);
1873
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001874 if (trace->sched &&
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301875 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1876 trace__sched_stat_runtime))
1877 goto out_error_tp;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001878
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001879 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1880 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001881 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001882 goto out_delete_evlist;
1883 }
1884
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001885 err = trace__symbols_init(trace, evlist);
1886 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001887 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001888 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001889 }
1890
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001891 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001892
Namhyung Kimf15eb532012-10-05 14:02:16 +09001893 signal(SIGCHLD, sig_handler);
1894 signal(SIGINT, sig_handler);
1895
1896 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001897 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001898 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001899 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001900 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001901 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001902 }
1903 }
1904
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001905 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03001906 if (err < 0)
1907 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001908
Jiri Olsaf8850372013-11-28 17:57:22 +01001909 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001910 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001911 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001912 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001913 }
1914
1915 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001916
1917 if (forks)
1918 perf_evlist__start_workload(evlist);
1919
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001920 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001921again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001922 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001923
1924 for (i = 0; i < evlist->nr_mmaps; i++) {
1925 union perf_event *event;
1926
1927 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1928 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001929 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001930 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001931
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001932 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001933
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001934 err = perf_evlist__parse_sample(evlist, event, &sample);
1935 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001936 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001937 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001938 }
1939
David Ahern4bb09192013-09-04 12:37:43 -06001940 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001941 trace->base_time = sample.time;
1942
1943 if (type != PERF_RECORD_SAMPLE) {
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001944 trace__process_event(trace, trace->host, event, &sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001945 continue;
1946 }
1947
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001948 evsel = perf_evlist__id2evsel(evlist, sample.id);
1949 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001950 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001951 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001952 }
1953
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001954 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001955 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 -03001956 perf_evsel__name(evsel), sample.tid,
1957 sample.cpu, sample.raw_size);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001958 goto next_event;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001959 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001960
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001961 handler = evsel->handler;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001962 handler(trace, evsel, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08001963next_event:
1964 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001965
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001966 if (interrupted)
1967 goto out_disable;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001968 }
1969 }
1970
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001971 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001972 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001973
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001974 if (poll(evlist->pollfd, evlist->nr_fds, timeout) > 0)
1975 goto again;
1976 } else {
1977 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001978 }
1979
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001980out_disable:
1981 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001982
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001983 if (!err) {
1984 if (trace->summary)
1985 trace__fprintf_thread_summary(trace, trace->output);
1986
1987 if (trace->show_tool_stats) {
1988 fprintf(trace->output, "Stats:\n "
1989 " vfs_getname : %" PRIu64 "\n"
1990 " proc_getname: %" PRIu64 "\n",
1991 trace->stats.vfs_getname,
1992 trace->stats.proc_getname);
1993 }
1994 }
David Ahernbf2575c2013-10-08 21:26:53 -06001995
Namhyung Kim3beb0862013-03-15 14:48:50 +09001996 perf_evlist__munmap(evlist);
1997out_close_evlist:
1998 perf_evlist__close(evlist);
1999out_delete_maps:
2000 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002001out_delete_evlist:
2002 perf_evlist__delete(evlist);
2003out:
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002004 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002005 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002006{
2007 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002008
2009out_error_tp:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002010 perf_evlist__strerror_tp(evlist, errno, errbuf, sizeof(errbuf));
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002011 goto out_error;
2012
2013out_error_open:
2014 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2015
2016out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002017 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302018 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002019}
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002020}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002021
David Ahern6810fc92013-08-28 22:29:52 -06002022static int trace__replay(struct trace *trace)
2023{
2024 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002025 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002026 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002027 struct perf_data_file file = {
2028 .path = input_name,
2029 .mode = PERF_DATA_MODE_READ,
2030 };
David Ahern6810fc92013-08-28 22:29:52 -06002031 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002032 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002033 int err = -1;
2034
2035 trace->tool.sample = trace__process_sample;
2036 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002037 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002038 trace->tool.comm = perf_event__process_comm;
2039 trace->tool.exit = perf_event__process_exit;
2040 trace->tool.fork = perf_event__process_fork;
2041 trace->tool.attr = perf_event__process_attr;
2042 trace->tool.tracing_data = perf_event__process_tracing_data;
2043 trace->tool.build_id = perf_event__process_build_id;
2044
2045 trace->tool.ordered_samples = true;
2046 trace->tool.ordering_requires_timestamps = true;
2047
2048 /* add tid to output */
2049 trace->multiple_threads = true;
2050
2051 if (symbol__init() < 0)
2052 return -1;
2053
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002054 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002055 if (session == NULL)
2056 return -ENOMEM;
2057
David Ahern8fb598e2013-09-28 13:13:00 -06002058 trace->host = &session->machines.host;
2059
David Ahern6810fc92013-08-28 22:29:52 -06002060 err = perf_session__set_tracepoints_handlers(session, handlers);
2061 if (err)
2062 goto out;
2063
Namhyung Kim003824e2013-11-12 15:25:00 +09002064 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2065 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002066 /* older kernels have syscalls tp versus raw_syscalls */
2067 if (evsel == NULL)
2068 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2069 "syscalls:sys_enter");
Namhyung Kim003824e2013-11-12 15:25:00 +09002070 if (evsel == NULL) {
2071 pr_err("Data file does not have raw_syscalls:sys_enter event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002072 goto out;
2073 }
2074
Namhyung Kim003824e2013-11-12 15:25:00 +09002075 if (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2076 perf_evsel__init_sc_tp_ptr_field(evsel, args)) {
2077 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2078 goto out;
2079 }
2080
2081 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2082 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002083 if (evsel == NULL)
2084 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2085 "syscalls:sys_exit");
Namhyung Kim003824e2013-11-12 15:25:00 +09002086 if (evsel == NULL) {
2087 pr_err("Data file does not have raw_syscalls:sys_exit event\n");
2088 goto out;
2089 }
2090
2091 if (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2092 perf_evsel__init_sc_tp_uint_field(evsel, ret)) {
2093 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002094 goto out;
2095 }
2096
David Ahernbdc89662013-08-28 22:29:53 -06002097 err = parse_target_str(trace);
2098 if (err != 0)
2099 goto out;
2100
David Ahern6810fc92013-08-28 22:29:52 -06002101 setup_pager();
2102
2103 err = perf_session__process_events(session, &trace->tool);
2104 if (err)
2105 pr_err("Failed to process events, error %d", err);
2106
David Ahernbf2575c2013-10-08 21:26:53 -06002107 else if (trace->summary)
2108 trace__fprintf_thread_summary(trace, trace->output);
2109
David Ahern6810fc92013-08-28 22:29:52 -06002110out:
2111 perf_session__delete(session);
2112
2113 return err;
2114}
2115
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002116static size_t trace__fprintf_threads_header(FILE *fp)
2117{
2118 size_t printed;
2119
Pekka Enberg99ff7152013-11-12 16:42:14 +02002120 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002121
2122 return printed;
2123}
2124
2125static size_t thread__dump_stats(struct thread_trace *ttrace,
2126 struct trace *trace, FILE *fp)
2127{
2128 struct stats *stats;
2129 size_t printed = 0;
2130 struct syscall *sc;
2131 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2132
2133 if (inode == NULL)
2134 return 0;
2135
2136 printed += fprintf(fp, "\n");
2137
Pekka Enberg27a778b2013-11-13 14:21:48 +02002138 printed += fprintf(fp, " syscall calls min avg max stddev\n");
2139 printed += fprintf(fp, " (msec) (msec) (msec) (%%)\n");
2140 printed += fprintf(fp, " --------------- -------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002141
David Ahernbf2575c2013-10-08 21:26:53 -06002142 /* each int_node is a syscall */
2143 while (inode) {
2144 stats = inode->priv;
2145 if (stats) {
2146 double min = (double)(stats->min) / NSEC_PER_MSEC;
2147 double max = (double)(stats->max) / NSEC_PER_MSEC;
2148 double avg = avg_stats(stats);
2149 double pct;
2150 u64 n = (u64) stats->n;
2151
2152 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2153 avg /= NSEC_PER_MSEC;
2154
2155 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002156 printed += fprintf(fp, " %-15s", sc->name);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002157 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f",
Pekka Enberg7f7a4132013-11-12 16:10:10 +02002158 n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002159 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002160 }
2161
2162 inode = intlist__next(inode);
2163 }
2164
2165 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002166
2167 return printed;
2168}
2169
David Ahern896cbb52013-09-28 13:12:59 -06002170/* struct used to pass data to per-thread function */
2171struct summary_data {
2172 FILE *fp;
2173 struct trace *trace;
2174 size_t printed;
2175};
2176
2177static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2178{
2179 struct summary_data *data = priv;
2180 FILE *fp = data->fp;
2181 size_t printed = data->printed;
2182 struct trace *trace = data->trace;
2183 struct thread_trace *ttrace = thread->priv;
David Ahern896cbb52013-09-28 13:12:59 -06002184 double ratio;
2185
2186 if (ttrace == NULL)
2187 return 0;
2188
2189 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2190
Pekka Enberg15e65c62013-11-14 18:43:30 +02002191 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002192 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002193 printed += fprintf(fp, "%.1f%%", ratio);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002194 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002195 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002196
2197 data->printed += printed;
2198
2199 return 0;
2200}
2201
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002202static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2203{
David Ahern896cbb52013-09-28 13:12:59 -06002204 struct summary_data data = {
2205 .fp = fp,
2206 .trace = trace
2207 };
2208 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002209
David Ahern896cbb52013-09-28 13:12:59 -06002210 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002211
David Ahern896cbb52013-09-28 13:12:59 -06002212 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002213}
2214
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002215static int trace__set_duration(const struct option *opt, const char *str,
2216 int unset __maybe_unused)
2217{
2218 struct trace *trace = opt->value;
2219
2220 trace->duration_filter = atof(str);
2221 return 0;
2222}
2223
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002224static int trace__open_output(struct trace *trace, const char *filename)
2225{
2226 struct stat st;
2227
2228 if (!stat(filename, &st) && st.st_size) {
2229 char oldname[PATH_MAX];
2230
2231 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2232 unlink(oldname);
2233 rename(filename, oldname);
2234 }
2235
2236 trace->output = fopen(filename, "w");
2237
2238 return trace->output == NULL ? -errno : 0;
2239}
2240
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002241int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2242{
2243 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002244 "perf trace [<options>] [<command>]",
2245 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002246 "perf trace record [<options>] [<command>]",
2247 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002248 NULL
2249 };
2250 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002251 .audit = {
2252 .machine = audit_detect_machine(),
2253 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2254 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002255 .syscalls = {
2256 . max = -1,
2257 },
2258 .opts = {
2259 .target = {
2260 .uid = UINT_MAX,
2261 .uses_mmap = true,
2262 },
2263 .user_freq = UINT_MAX,
2264 .user_interval = ULLONG_MAX,
2265 .no_delay = true,
2266 .mmap_pages = 1024,
2267 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002268 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002269 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002270 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002271 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002272 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002273 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002274 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2275 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002276 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002277 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
2278 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002279 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002280 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002281 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2282 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002283 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002284 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002285 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002286 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002287 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002288 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002289 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002290 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002291 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2292 "number of mmap data pages",
2293 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002294 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002295 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002296 OPT_CALLBACK(0, "duration", &trace, "float",
2297 "show only events with duration > N.M ms",
2298 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002299 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002300 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002301 OPT_BOOLEAN('T', "time", &trace.full_time,
2302 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002303 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2304 "Show only syscall summary with statistics"),
2305 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2306 "Show all syscalls and summary with statistics"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002307 OPT_END()
2308 };
2309 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002310 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002311
David Ahern5e2485b2013-09-28 13:13:01 -06002312 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
2313 return trace__record(argc-2, &argv[2]);
2314
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002315 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002316
David Ahernfd2eaba2013-11-12 09:31:15 -07002317 /* summary_only implies summary option, but don't overwrite summary if set */
2318 if (trace.summary_only)
2319 trace.summary = trace.summary_only;
2320
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002321 if (output_name != NULL) {
2322 err = trace__open_output(&trace, output_name);
2323 if (err < 0) {
2324 perror("failed to create output file");
2325 goto out;
2326 }
2327 }
2328
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002329 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002330 const char *s = ev_qualifier_str;
2331
2332 trace.not_ev_qualifier = *s == '!';
2333 if (trace.not_ev_qualifier)
2334 ++s;
2335 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002336 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002337 fputs("Not enough memory to parse event qualifier",
2338 trace.output);
2339 err = -ENOMEM;
2340 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002341 }
2342 }
2343
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002344 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002345 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002346 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002347 fprintf(trace.output, "%s", bf);
2348 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002349 }
2350
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002351 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002352 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002353 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002354 fprintf(trace.output, "%s", bf);
2355 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002356 }
2357
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002358 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002359 trace.opts.target.system_wide = true;
2360
David Ahern6810fc92013-08-28 22:29:52 -06002361 if (input_name)
2362 err = trace__replay(&trace);
2363 else
2364 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002365
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002366out_close:
2367 if (output_name != NULL)
2368 fclose(trace.output);
2369out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002370 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002371}