blob: a05490d06374d30a6488781adf0e2f812b48fcb7 [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 Meloae685382013-08-20 17:44:42 -030019#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030020#include <linux/futex.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021
Ingo Molnar456857b2013-09-12 15:29:00 +020022/* For older distros: */
23#ifndef MAP_STACK
24# define MAP_STACK 0x20000
25#endif
26
27#ifndef MADV_HWPOISON
28# define MADV_HWPOISON 100
29#endif
30
31#ifndef MADV_MERGEABLE
32# define MADV_MERGEABLE 12
33#endif
34
35#ifndef MADV_UNMERGEABLE
36# define MADV_UNMERGEABLE 13
37#endif
38
Ben Hutchings79d26a62014-02-06 01:00:35 +000039#ifndef EFD_SEMAPHORE
40# define EFD_SEMAPHORE 1
41#endif
42
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030043#ifndef EFD_NONBLOCK
44# define EFD_NONBLOCK 00004000
45#endif
46
47#ifndef EFD_CLOEXEC
48# define EFD_CLOEXEC 02000000
49#endif
50
51#ifndef O_CLOEXEC
52# define O_CLOEXEC 02000000
53#endif
54
55#ifndef SOCK_DCCP
56# define SOCK_DCCP 6
57#endif
58
59#ifndef SOCK_CLOEXEC
60# define SOCK_CLOEXEC 02000000
61#endif
62
63#ifndef SOCK_NONBLOCK
64# define SOCK_NONBLOCK 00004000
65#endif
66
67#ifndef MSG_CMSG_CLOEXEC
68# define MSG_CMSG_CLOEXEC 0x40000000
69#endif
70
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -030071struct tp_field {
72 int offset;
73 union {
74 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
75 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
76 };
77};
78
79#define TP_UINT_FIELD(bits) \
80static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
81{ \
David Ahern55d43bc2015-02-19 15:00:22 -050082 u##bits value; \
83 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
84 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -030085}
86
87TP_UINT_FIELD(8);
88TP_UINT_FIELD(16);
89TP_UINT_FIELD(32);
90TP_UINT_FIELD(64);
91
92#define TP_UINT_FIELD__SWAPPED(bits) \
93static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
94{ \
David Ahern55d43bc2015-02-19 15:00:22 -050095 u##bits value; \
96 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -030097 return bswap_##bits(value);\
98}
99
100TP_UINT_FIELD__SWAPPED(16);
101TP_UINT_FIELD__SWAPPED(32);
102TP_UINT_FIELD__SWAPPED(64);
103
104static int tp_field__init_uint(struct tp_field *field,
105 struct format_field *format_field,
106 bool needs_swap)
107{
108 field->offset = format_field->offset;
109
110 switch (format_field->size) {
111 case 1:
112 field->integer = tp_field__u8;
113 break;
114 case 2:
115 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
116 break;
117 case 4:
118 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
119 break;
120 case 8:
121 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
122 break;
123 default:
124 return -1;
125 }
126
127 return 0;
128}
129
130static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
131{
132 return sample->raw_data + field->offset;
133}
134
135static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
136{
137 field->offset = format_field->offset;
138 field->pointer = tp_field__ptr;
139 return 0;
140}
141
142struct syscall_tp {
143 struct tp_field id;
144 union {
145 struct tp_field args, ret;
146 };
147};
148
149static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
150 struct tp_field *field,
151 const char *name)
152{
153 struct format_field *format_field = perf_evsel__field(evsel, name);
154
155 if (format_field == NULL)
156 return -1;
157
158 return tp_field__init_uint(field, format_field, evsel->needs_swap);
159}
160
161#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
162 ({ struct syscall_tp *sc = evsel->priv;\
163 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
164
165static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
166 struct tp_field *field,
167 const char *name)
168{
169 struct format_field *format_field = perf_evsel__field(evsel, name);
170
171 if (format_field == NULL)
172 return -1;
173
174 return tp_field__init_ptr(field, format_field);
175}
176
177#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
178 ({ struct syscall_tp *sc = evsel->priv;\
179 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
180
181static void perf_evsel__delete_priv(struct perf_evsel *evsel)
182{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300183 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300184 perf_evsel__delete(evsel);
185}
186
Namhyung Kim96695d42013-11-12 08:51:45 -0300187static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
188{
189 evsel->priv = malloc(sizeof(struct syscall_tp));
190 if (evsel->priv != NULL) {
191 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
192 goto out_delete;
193
194 evsel->handler = handler;
195 return 0;
196 }
197
198 return -ENOMEM;
199
200out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300201 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300202 return -ENOENT;
203}
204
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300205static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300206{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300207 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300208
David Ahern9aca7f12013-12-04 19:41:39 -0700209 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
210 if (evsel == NULL)
211 evsel = perf_evsel__newtp("syscalls", direction);
212
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300213 if (evsel) {
Namhyung Kim96695d42013-11-12 08:51:45 -0300214 if (perf_evsel__init_syscall_tp(evsel, handler))
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300215 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300216 }
217
218 return evsel;
219
220out_delete:
221 perf_evsel__delete_priv(evsel);
222 return NULL;
223}
224
225#define perf_evsel__sc_tp_uint(evsel, name, sample) \
226 ({ struct syscall_tp *fields = evsel->priv; \
227 fields->name.integer(&fields->name, sample); })
228
229#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
230 ({ struct syscall_tp *fields = evsel->priv; \
231 fields->name.pointer(&fields->name, sample); })
232
233static int perf_evlist__add_syscall_newtp(struct perf_evlist *evlist,
234 void *sys_enter_handler,
235 void *sys_exit_handler)
236{
237 int ret = -1;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300238 struct perf_evsel *sys_enter, *sys_exit;
239
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300240 sys_enter = perf_evsel__syscall_newtp("sys_enter", sys_enter_handler);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300241 if (sys_enter == NULL)
242 goto out;
243
244 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
245 goto out_delete_sys_enter;
246
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300247 sys_exit = perf_evsel__syscall_newtp("sys_exit", sys_exit_handler);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300248 if (sys_exit == NULL)
249 goto out_delete_sys_enter;
250
251 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
252 goto out_delete_sys_exit;
253
254 perf_evlist__add(evlist, sys_enter);
255 perf_evlist__add(evlist, sys_exit);
256
257 ret = 0;
258out:
259 return ret;
260
261out_delete_sys_exit:
262 perf_evsel__delete_priv(sys_exit);
263out_delete_sys_enter:
264 perf_evsel__delete_priv(sys_enter);
265 goto out;
266}
267
268
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300269struct syscall_arg {
270 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300271 struct thread *thread;
272 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300273 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300274 u8 idx;
275 u8 mask;
276};
277
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300278struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300279 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300280 int nr_entries;
281 const char **entries;
282};
283
284#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
285 .nr_entries = ARRAY_SIZE(array), \
286 .entries = array, \
287}
288
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300289#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
290 .offset = off, \
291 .nr_entries = ARRAY_SIZE(array), \
292 .entries = array, \
293}
294
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300295static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
296 const char *intfmt,
297 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300298{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300299 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300300 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300301
302 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300303 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300304
305 return scnprintf(bf, size, "%s", sa->entries[idx]);
306}
307
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300308static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
309 struct syscall_arg *arg)
310{
311 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
312}
313
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300314#define SCA_STRARRAY syscall_arg__scnprintf_strarray
315
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300316#if defined(__i386__) || defined(__x86_64__)
317/*
318 * FIXME: Make this available to all arches as soon as the ioctl beautifier
319 * gets rewritten to support all arches.
320 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300321static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
322 struct syscall_arg *arg)
323{
324 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
325}
326
327#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300328#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300329
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300330static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
331 struct syscall_arg *arg);
332
333#define SCA_FD syscall_arg__scnprintf_fd
334
335static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
336 struct syscall_arg *arg)
337{
338 int fd = arg->val;
339
340 if (fd == AT_FDCWD)
341 return scnprintf(bf, size, "CWD");
342
343 return syscall_arg__scnprintf_fd(bf, size, arg);
344}
345
346#define SCA_FDAT syscall_arg__scnprintf_fd_at
347
348static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
349 struct syscall_arg *arg);
350
351#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
352
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300353static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300354 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300355{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300356 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300357}
358
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300359#define SCA_HEX syscall_arg__scnprintf_hex
360
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300361static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300362 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300363{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300364 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300365
366 if (prot == PROT_NONE)
367 return scnprintf(bf, size, "NONE");
368#define P_MMAP_PROT(n) \
369 if (prot & PROT_##n) { \
370 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
371 prot &= ~PROT_##n; \
372 }
373
374 P_MMAP_PROT(EXEC);
375 P_MMAP_PROT(READ);
376 P_MMAP_PROT(WRITE);
377#ifdef PROT_SEM
378 P_MMAP_PROT(SEM);
379#endif
380 P_MMAP_PROT(GROWSDOWN);
381 P_MMAP_PROT(GROWSUP);
382#undef P_MMAP_PROT
383
384 if (prot)
385 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
386
387 return printed;
388}
389
390#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
391
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300392static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300393 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300394{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300395 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300396
397#define P_MMAP_FLAG(n) \
398 if (flags & MAP_##n) { \
399 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
400 flags &= ~MAP_##n; \
401 }
402
403 P_MMAP_FLAG(SHARED);
404 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400405#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300406 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400407#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300408 P_MMAP_FLAG(ANONYMOUS);
409 P_MMAP_FLAG(DENYWRITE);
410 P_MMAP_FLAG(EXECUTABLE);
411 P_MMAP_FLAG(FILE);
412 P_MMAP_FLAG(FIXED);
413 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600414#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300415 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600416#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300417 P_MMAP_FLAG(LOCKED);
418 P_MMAP_FLAG(NONBLOCK);
419 P_MMAP_FLAG(NORESERVE);
420 P_MMAP_FLAG(POPULATE);
421 P_MMAP_FLAG(STACK);
422#ifdef MAP_UNINITIALIZED
423 P_MMAP_FLAG(UNINITIALIZED);
424#endif
425#undef P_MMAP_FLAG
426
427 if (flags)
428 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
429
430 return printed;
431}
432
433#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
434
Alex Snast86998dd2014-08-13 18:42:40 +0300435static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
436 struct syscall_arg *arg)
437{
438 int printed = 0, flags = arg->val;
439
440#define P_MREMAP_FLAG(n) \
441 if (flags & MREMAP_##n) { \
442 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
443 flags &= ~MREMAP_##n; \
444 }
445
446 P_MREMAP_FLAG(MAYMOVE);
447#ifdef MREMAP_FIXED
448 P_MREMAP_FLAG(FIXED);
449#endif
450#undef P_MREMAP_FLAG
451
452 if (flags)
453 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
454
455 return printed;
456}
457
458#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
459
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300460static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300461 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300462{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300463 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300464
465 switch (behavior) {
466#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
467 P_MADV_BHV(NORMAL);
468 P_MADV_BHV(RANDOM);
469 P_MADV_BHV(SEQUENTIAL);
470 P_MADV_BHV(WILLNEED);
471 P_MADV_BHV(DONTNEED);
472 P_MADV_BHV(REMOVE);
473 P_MADV_BHV(DONTFORK);
474 P_MADV_BHV(DOFORK);
475 P_MADV_BHV(HWPOISON);
476#ifdef MADV_SOFT_OFFLINE
477 P_MADV_BHV(SOFT_OFFLINE);
478#endif
479 P_MADV_BHV(MERGEABLE);
480 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600481#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300482 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600483#endif
484#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300485 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600486#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300487#ifdef MADV_DONTDUMP
488 P_MADV_BHV(DONTDUMP);
489#endif
490#ifdef MADV_DODUMP
491 P_MADV_BHV(DODUMP);
492#endif
493#undef P_MADV_PHV
494 default: break;
495 }
496
497 return scnprintf(bf, size, "%#x", behavior);
498}
499
500#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
501
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300502static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
503 struct syscall_arg *arg)
504{
505 int printed = 0, op = arg->val;
506
507 if (op == 0)
508 return scnprintf(bf, size, "NONE");
509#define P_CMD(cmd) \
510 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
511 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
512 op &= ~LOCK_##cmd; \
513 }
514
515 P_CMD(SH);
516 P_CMD(EX);
517 P_CMD(NB);
518 P_CMD(UN);
519 P_CMD(MAND);
520 P_CMD(RW);
521 P_CMD(READ);
522 P_CMD(WRITE);
523#undef P_OP
524
525 if (op)
526 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
527
528 return printed;
529}
530
531#define SCA_FLOCK syscall_arg__scnprintf_flock
532
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300533static 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 -0300534{
535 enum syscall_futex_args {
536 SCF_UADDR = (1 << 0),
537 SCF_OP = (1 << 1),
538 SCF_VAL = (1 << 2),
539 SCF_TIMEOUT = (1 << 3),
540 SCF_UADDR2 = (1 << 4),
541 SCF_VAL3 = (1 << 5),
542 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300543 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300544 int cmd = op & FUTEX_CMD_MASK;
545 size_t printed = 0;
546
547 switch (cmd) {
548#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300549 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
550 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
551 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
552 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
553 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
554 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300555 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300556 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
557 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
558 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
559 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
560 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300561 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
562 default: printed = scnprintf(bf, size, "%#x", cmd); break;
563 }
564
565 if (op & FUTEX_PRIVATE_FLAG)
566 printed += scnprintf(bf + printed, size - printed, "|PRIV");
567
568 if (op & FUTEX_CLOCK_REALTIME)
569 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
570
571 return printed;
572}
573
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300574#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
575
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300576static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
577static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300578
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300579static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
580static DEFINE_STRARRAY(itimers);
581
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300582static const char *whences[] = { "SET", "CUR", "END",
583#ifdef SEEK_DATA
584"DATA",
585#endif
586#ifdef SEEK_HOLE
587"HOLE",
588#endif
589};
590static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300591
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300592static const char *fcntl_cmds[] = {
593 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
594 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
595 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
596 "F_GETOWNER_UIDS",
597};
598static DEFINE_STRARRAY(fcntl_cmds);
599
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300600static const char *rlimit_resources[] = {
601 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
602 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
603 "RTTIME",
604};
605static DEFINE_STRARRAY(rlimit_resources);
606
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300607static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
608static DEFINE_STRARRAY(sighow);
609
David Ahern4f8c1b72013-09-22 19:45:00 -0600610static const char *clockid[] = {
611 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
612 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
613};
614static DEFINE_STRARRAY(clockid);
615
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300616static const char *socket_families[] = {
617 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
618 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
619 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
620 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
621 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
622 "ALG", "NFC", "VSOCK",
623};
624static DEFINE_STRARRAY(socket_families);
625
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300626#ifndef SOCK_TYPE_MASK
627#define SOCK_TYPE_MASK 0xf
628#endif
629
630static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
631 struct syscall_arg *arg)
632{
633 size_t printed;
634 int type = arg->val,
635 flags = type & ~SOCK_TYPE_MASK;
636
637 type &= SOCK_TYPE_MASK;
638 /*
639 * Can't use a strarray, MIPS may override for ABI reasons.
640 */
641 switch (type) {
642#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
643 P_SK_TYPE(STREAM);
644 P_SK_TYPE(DGRAM);
645 P_SK_TYPE(RAW);
646 P_SK_TYPE(RDM);
647 P_SK_TYPE(SEQPACKET);
648 P_SK_TYPE(DCCP);
649 P_SK_TYPE(PACKET);
650#undef P_SK_TYPE
651 default:
652 printed = scnprintf(bf, size, "%#x", type);
653 }
654
655#define P_SK_FLAG(n) \
656 if (flags & SOCK_##n) { \
657 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
658 flags &= ~SOCK_##n; \
659 }
660
661 P_SK_FLAG(CLOEXEC);
662 P_SK_FLAG(NONBLOCK);
663#undef P_SK_FLAG
664
665 if (flags)
666 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
667
668 return printed;
669}
670
671#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
672
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300673#ifndef MSG_PROBE
674#define MSG_PROBE 0x10
675#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600676#ifndef MSG_WAITFORONE
677#define MSG_WAITFORONE 0x10000
678#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300679#ifndef MSG_SENDPAGE_NOTLAST
680#define MSG_SENDPAGE_NOTLAST 0x20000
681#endif
682#ifndef MSG_FASTOPEN
683#define MSG_FASTOPEN 0x20000000
684#endif
685
686static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
687 struct syscall_arg *arg)
688{
689 int printed = 0, flags = arg->val;
690
691 if (flags == 0)
692 return scnprintf(bf, size, "NONE");
693#define P_MSG_FLAG(n) \
694 if (flags & MSG_##n) { \
695 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
696 flags &= ~MSG_##n; \
697 }
698
699 P_MSG_FLAG(OOB);
700 P_MSG_FLAG(PEEK);
701 P_MSG_FLAG(DONTROUTE);
702 P_MSG_FLAG(TRYHARD);
703 P_MSG_FLAG(CTRUNC);
704 P_MSG_FLAG(PROBE);
705 P_MSG_FLAG(TRUNC);
706 P_MSG_FLAG(DONTWAIT);
707 P_MSG_FLAG(EOR);
708 P_MSG_FLAG(WAITALL);
709 P_MSG_FLAG(FIN);
710 P_MSG_FLAG(SYN);
711 P_MSG_FLAG(CONFIRM);
712 P_MSG_FLAG(RST);
713 P_MSG_FLAG(ERRQUEUE);
714 P_MSG_FLAG(NOSIGNAL);
715 P_MSG_FLAG(MORE);
716 P_MSG_FLAG(WAITFORONE);
717 P_MSG_FLAG(SENDPAGE_NOTLAST);
718 P_MSG_FLAG(FASTOPEN);
719 P_MSG_FLAG(CMSG_CLOEXEC);
720#undef P_MSG_FLAG
721
722 if (flags)
723 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
724
725 return printed;
726}
727
728#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
729
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300730static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
731 struct syscall_arg *arg)
732{
733 size_t printed = 0;
734 int mode = arg->val;
735
736 if (mode == F_OK) /* 0 */
737 return scnprintf(bf, size, "F");
738#define P_MODE(n) \
739 if (mode & n##_OK) { \
740 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
741 mode &= ~n##_OK; \
742 }
743
744 P_MODE(R);
745 P_MODE(W);
746 P_MODE(X);
747#undef P_MODE
748
749 if (mode)
750 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
751
752 return printed;
753}
754
755#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
756
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300757static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300758 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300759{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300760 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300761
762 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300763 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300764
765 if (flags == 0)
766 return scnprintf(bf, size, "RDONLY");
767#define P_FLAG(n) \
768 if (flags & O_##n) { \
769 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
770 flags &= ~O_##n; \
771 }
772
773 P_FLAG(APPEND);
774 P_FLAG(ASYNC);
775 P_FLAG(CLOEXEC);
776 P_FLAG(CREAT);
777 P_FLAG(DIRECT);
778 P_FLAG(DIRECTORY);
779 P_FLAG(EXCL);
780 P_FLAG(LARGEFILE);
781 P_FLAG(NOATIME);
782 P_FLAG(NOCTTY);
783#ifdef O_NONBLOCK
784 P_FLAG(NONBLOCK);
785#elif O_NDELAY
786 P_FLAG(NDELAY);
787#endif
788#ifdef O_PATH
789 P_FLAG(PATH);
790#endif
791 P_FLAG(RDWR);
792#ifdef O_DSYNC
793 if ((flags & O_SYNC) == O_SYNC)
794 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
795 else {
796 P_FLAG(DSYNC);
797 }
798#else
799 P_FLAG(SYNC);
800#endif
801 P_FLAG(TRUNC);
802 P_FLAG(WRONLY);
803#undef P_FLAG
804
805 if (flags)
806 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
807
808 return printed;
809}
810
811#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
812
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300813static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
814 struct syscall_arg *arg)
815{
816 int printed = 0, flags = arg->val;
817
818 if (flags == 0)
819 return scnprintf(bf, size, "NONE");
820#define P_FLAG(n) \
821 if (flags & EFD_##n) { \
822 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
823 flags &= ~EFD_##n; \
824 }
825
826 P_FLAG(SEMAPHORE);
827 P_FLAG(CLOEXEC);
828 P_FLAG(NONBLOCK);
829#undef P_FLAG
830
831 if (flags)
832 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
833
834 return printed;
835}
836
837#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
838
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300839static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
840 struct syscall_arg *arg)
841{
842 int printed = 0, flags = arg->val;
843
844#define P_FLAG(n) \
845 if (flags & O_##n) { \
846 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
847 flags &= ~O_##n; \
848 }
849
850 P_FLAG(CLOEXEC);
851 P_FLAG(NONBLOCK);
852#undef P_FLAG
853
854 if (flags)
855 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
856
857 return printed;
858}
859
860#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
861
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300862static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
863{
864 int sig = arg->val;
865
866 switch (sig) {
867#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
868 P_SIGNUM(HUP);
869 P_SIGNUM(INT);
870 P_SIGNUM(QUIT);
871 P_SIGNUM(ILL);
872 P_SIGNUM(TRAP);
873 P_SIGNUM(ABRT);
874 P_SIGNUM(BUS);
875 P_SIGNUM(FPE);
876 P_SIGNUM(KILL);
877 P_SIGNUM(USR1);
878 P_SIGNUM(SEGV);
879 P_SIGNUM(USR2);
880 P_SIGNUM(PIPE);
881 P_SIGNUM(ALRM);
882 P_SIGNUM(TERM);
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300883 P_SIGNUM(CHLD);
884 P_SIGNUM(CONT);
885 P_SIGNUM(STOP);
886 P_SIGNUM(TSTP);
887 P_SIGNUM(TTIN);
888 P_SIGNUM(TTOU);
889 P_SIGNUM(URG);
890 P_SIGNUM(XCPU);
891 P_SIGNUM(XFSZ);
892 P_SIGNUM(VTALRM);
893 P_SIGNUM(PROF);
894 P_SIGNUM(WINCH);
895 P_SIGNUM(IO);
896 P_SIGNUM(PWR);
897 P_SIGNUM(SYS);
Ben Hutchings02c5bb42014-02-06 01:00:41 +0000898#ifdef SIGEMT
899 P_SIGNUM(EMT);
900#endif
901#ifdef SIGSTKFLT
902 P_SIGNUM(STKFLT);
903#endif
904#ifdef SIGSWI
905 P_SIGNUM(SWI);
906#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300907 default: break;
908 }
909
910 return scnprintf(bf, size, "%#x", sig);
911}
912
913#define SCA_SIGNUM syscall_arg__scnprintf_signum
914
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300915#if defined(__i386__) || defined(__x86_64__)
916/*
917 * FIXME: Make this available to all arches.
918 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300919#define TCGETS 0x5401
920
921static const char *tioctls[] = {
922 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
923 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
924 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
925 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
926 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
927 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
928 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
929 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
930 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
931 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
932 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
933 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
934 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
935 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
936 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
937};
938
939static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300940#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300941
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300942#define STRARRAY(arg, name, array) \
943 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
944 .arg_parm = { [arg] = &strarray__##array, }
945
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300946static struct syscall_fmt {
947 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300948 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300949 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300950 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300951 bool errmsg;
952 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300953 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300954} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300955 { .name = "access", .errmsg = true,
956 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300957 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300958 { .name = "brk", .hexret = true,
959 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600960 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300961 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300962 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300963 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300964 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300965 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300966 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300967 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300968 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300969 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300970 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300971 { .name = "eventfd2", .errmsg = true,
972 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300973 { .name = "faccessat", .errmsg = true,
974 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
975 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300976 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300977 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300978 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300979 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300980 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300981 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300982 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300983 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300984 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300985 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300986 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300987 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300988 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300989 { .name = "fcntl", .errmsg = true,
990 .arg_scnprintf = { [0] = SCA_FD, /* fd */
991 [1] = SCA_STRARRAY, /* cmd */ },
992 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
993 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300994 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300995 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300996 .arg_scnprintf = { [0] = SCA_FD, /* fd */
997 [1] = SCA_FLOCK, /* cmd */ }, },
998 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300999 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001000 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001001 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001002 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001003 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001004 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001005 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001006 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001007 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001008 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001009 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -03001010 { .name = "futex", .errmsg = true,
1011 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001012 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001013 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001014 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001015 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001016 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001017 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001018 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1019 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001020 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001021 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001022#if defined(__i386__) || defined(__x86_64__)
1023/*
1024 * FIXME: Make this available to all arches.
1025 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001026 [1] = SCA_STRHEXARRAY, /* cmd */
1027 [2] = SCA_HEX, /* arg */ },
1028 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001029#else
1030 [2] = SCA_HEX, /* arg */ }, },
1031#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001032 { .name = "kill", .errmsg = true,
1033 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001034 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001035 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001036 { .name = "lseek", .errmsg = true,
1037 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1038 [2] = SCA_STRARRAY, /* whence */ },
1039 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001040 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001041 { .name = "madvise", .errmsg = true,
1042 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1043 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001044 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001045 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001046 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001047 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001048 { .name = "mlock", .errmsg = true,
1049 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1050 { .name = "mlockall", .errmsg = true,
1051 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001052 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001053 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001054 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001055 [3] = SCA_MMAP_FLAGS, /* flags */
1056 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001057 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001058 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1059 [2] = SCA_MMAP_PROT, /* prot */ }, },
1060 { .name = "mremap", .hexret = true,
1061 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001062 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001063 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001064 { .name = "munlock", .errmsg = true,
1065 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001066 { .name = "munmap", .errmsg = true,
1067 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001068 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001069 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001070 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001071 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001072 { .name = "open", .errmsg = true,
1073 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001074 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001075 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1076 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001077 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001078 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1079 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001080 { .name = "pipe2", .errmsg = true,
1081 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001082 { .name = "poll", .errmsg = true, .timeout = true, },
1083 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001084 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001085 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001086 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001087 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001088 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001089 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001090 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001091 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001092 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001093 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001094 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001095 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001096 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001097 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001098 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001099 { .name = "recvfrom", .errmsg = true,
1100 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1101 { .name = "recvmmsg", .errmsg = true,
1102 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1103 { .name = "recvmsg", .errmsg = true,
1104 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001105 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001106 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001107 { .name = "rt_sigaction", .errmsg = true,
1108 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001109 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001110 { .name = "rt_sigqueueinfo", .errmsg = true,
1111 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1112 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1113 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001114 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001115 { .name = "sendmmsg", .errmsg = true,
1116 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1117 { .name = "sendmsg", .errmsg = true,
1118 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
1119 { .name = "sendto", .errmsg = true,
1120 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001121 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1122 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001123 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001124 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001125 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001126 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1127 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001128 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001129 { .name = "socketpair", .errmsg = true,
1130 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1131 [1] = SCA_SK_TYPE, /* type */ },
1132 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001133 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001134 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001135 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001136 { .name = "tgkill", .errmsg = true,
1137 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1138 { .name = "tkill", .errmsg = true,
1139 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001140 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001141 { .name = "unlinkat", .errmsg = true,
1142 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1143 { .name = "utimensat", .errmsg = true,
1144 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
1145 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001146 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001147 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001148 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001149};
1150
1151static int syscall_fmt__cmp(const void *name, const void *fmtp)
1152{
1153 const struct syscall_fmt *fmt = fmtp;
1154 return strcmp(name, fmt->name);
1155}
1156
1157static struct syscall_fmt *syscall_fmt__find(const char *name)
1158{
1159 const int nmemb = ARRAY_SIZE(syscall_fmts);
1160 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1161}
1162
1163struct syscall {
1164 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001165 int nr_args;
1166 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001167 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001168 bool filtered;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001169 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001170 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001171 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001172 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001173};
1174
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001175static size_t fprintf_duration(unsigned long t, FILE *fp)
1176{
1177 double duration = (double)t / NSEC_PER_MSEC;
1178 size_t printed = fprintf(fp, "(");
1179
1180 if (duration >= 1.0)
1181 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1182 else if (duration >= 0.01)
1183 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1184 else
1185 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001186 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001187}
1188
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001189struct thread_trace {
1190 u64 entry_time;
1191 u64 exit_time;
1192 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001193 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001194 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001195 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001196 double runtime_ms;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001197 struct {
1198 int max;
1199 char **table;
1200 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001201
1202 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001203};
1204
1205static struct thread_trace *thread_trace__new(void)
1206{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001207 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1208
1209 if (ttrace)
1210 ttrace->paths.max = -1;
1211
David Ahernbf2575c2013-10-08 21:26:53 -06001212 ttrace->syscall_stats = intlist__new(NULL);
1213
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001214 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001215}
1216
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001217static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001218{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001219 struct thread_trace *ttrace;
1220
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001221 if (thread == NULL)
1222 goto fail;
1223
Namhyung Kim89dceb22014-10-06 09:46:03 +09001224 if (thread__priv(thread) == NULL)
1225 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001226
Namhyung Kim89dceb22014-10-06 09:46:03 +09001227 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001228 goto fail;
1229
Namhyung Kim89dceb22014-10-06 09:46:03 +09001230 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001231 ++ttrace->nr_events;
1232
1233 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001234fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001235 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001236 "WARNING: not enough memory, dropping samples!\n");
1237 return NULL;
1238}
1239
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001240#define TRACE_PFMAJ (1 << 0)
1241#define TRACE_PFMIN (1 << 1)
1242
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001243struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001244 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001245 struct {
1246 int machine;
1247 int open_id;
1248 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001249 struct {
1250 int max;
1251 struct syscall *table;
1252 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001253 struct record_opts opts;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001254 struct perf_evlist *evlist;
David Ahern8fb598e2013-09-28 13:13:00 -06001255 struct machine *host;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001256 struct thread *current;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001257 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001258 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001259 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001260 struct strlist *ev_qualifier;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001261 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -06001262 struct intlist *tid_list;
1263 struct intlist *pid_list;
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08001264 struct {
1265 size_t nr;
1266 pid_t *entries;
1267 } filter_pids;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001268 double duration_filter;
1269 double runtime_ms;
1270 struct {
1271 u64 vfs_getname,
1272 proc_getname;
1273 } stats;
1274 bool not_ev_qualifier;
1275 bool live;
1276 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001277 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001278 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001279 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001280 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001281 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001282 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001283 bool trace_syscalls;
Yunlong Songe366a6d2015-04-02 21:47:18 +08001284 bool force;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001285 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001286};
1287
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001288static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001289{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001290 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001291
1292 if (fd > ttrace->paths.max) {
1293 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1294
1295 if (npath == NULL)
1296 return -1;
1297
1298 if (ttrace->paths.max != -1) {
1299 memset(npath + ttrace->paths.max + 1, 0,
1300 (fd - ttrace->paths.max) * sizeof(char *));
1301 } else {
1302 memset(npath, 0, (fd + 1) * sizeof(char *));
1303 }
1304
1305 ttrace->paths.table = npath;
1306 ttrace->paths.max = fd;
1307 }
1308
1309 ttrace->paths.table[fd] = strdup(pathname);
1310
1311 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1312}
1313
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001314static int thread__read_fd_path(struct thread *thread, int fd)
1315{
1316 char linkname[PATH_MAX], pathname[PATH_MAX];
1317 struct stat st;
1318 int ret;
1319
1320 if (thread->pid_ == thread->tid) {
1321 scnprintf(linkname, sizeof(linkname),
1322 "/proc/%d/fd/%d", thread->pid_, fd);
1323 } else {
1324 scnprintf(linkname, sizeof(linkname),
1325 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1326 }
1327
1328 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1329 return -1;
1330
1331 ret = readlink(linkname, pathname, sizeof(pathname));
1332
1333 if (ret < 0 || ret > st.st_size)
1334 return -1;
1335
1336 pathname[ret] = '\0';
1337 return trace__set_fd_pathname(thread, fd, pathname);
1338}
1339
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001340static const char *thread__fd_path(struct thread *thread, int fd,
1341 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001342{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001343 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001344
1345 if (ttrace == NULL)
1346 return NULL;
1347
1348 if (fd < 0)
1349 return NULL;
1350
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001351 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001352 if (!trace->live)
1353 return NULL;
1354 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001355 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001356 return NULL;
1357 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001358
1359 return ttrace->paths.table[fd];
1360}
1361
1362static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1363 struct syscall_arg *arg)
1364{
1365 int fd = arg->val;
1366 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001367 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001368
1369 if (path)
1370 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1371
1372 return printed;
1373}
1374
1375static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1376 struct syscall_arg *arg)
1377{
1378 int fd = arg->val;
1379 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001380 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001381
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001382 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1383 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001384
1385 return printed;
1386}
1387
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001388static bool trace__filter_duration(struct trace *trace, double t)
1389{
1390 return t < (trace->duration_filter * NSEC_PER_MSEC);
1391}
1392
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001393static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1394{
1395 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1396
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001397 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001398}
1399
Namhyung Kimf15eb532012-10-05 14:02:16 +09001400static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001401static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001402
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001403static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001404{
1405 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001406 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001407}
1408
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001409static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001410 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001411{
1412 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001413 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001414
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001415 if (trace->multiple_threads) {
1416 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001417 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001418 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001419 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001420
1421 return printed;
1422}
1423
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001424static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001425 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001426{
1427 int ret = 0;
1428
1429 switch (event->header.type) {
1430 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001431 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001432 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001433 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001434 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001435 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001436 break;
1437 }
1438
1439 return ret;
1440}
1441
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001442static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001443 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001444 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001445 struct machine *machine)
1446{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001447 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001448 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001449}
1450
1451static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1452{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001453 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001454
1455 if (err)
1456 return err;
1457
David Ahern8fb598e2013-09-28 13:13:00 -06001458 trace->host = machine__new_host();
1459 if (trace->host == NULL)
1460 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001461
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001462 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
1463 evlist->threads, trace__tool_process, false);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001464 if (err)
1465 symbol__exit();
1466
1467 return err;
1468}
1469
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001470static int syscall__set_arg_fmts(struct syscall *sc)
1471{
1472 struct format_field *field;
1473 int idx = 0;
1474
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001475 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001476 if (sc->arg_scnprintf == NULL)
1477 return -1;
1478
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001479 if (sc->fmt)
1480 sc->arg_parm = sc->fmt->arg_parm;
1481
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001482 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001483 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1484 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1485 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001486 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1487 ++idx;
1488 }
1489
1490 return 0;
1491}
1492
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001493static int trace__read_syscall_info(struct trace *trace, int id)
1494{
1495 char tp_name[128];
1496 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001497 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001498
1499 if (name == NULL)
1500 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001501
1502 if (id > trace->syscalls.max) {
1503 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1504
1505 if (nsyscalls == NULL)
1506 return -1;
1507
1508 if (trace->syscalls.max != -1) {
1509 memset(nsyscalls + trace->syscalls.max + 1, 0,
1510 (id - trace->syscalls.max) * sizeof(*sc));
1511 } else {
1512 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1513 }
1514
1515 trace->syscalls.table = nsyscalls;
1516 trace->syscalls.max = id;
1517 }
1518
1519 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001520 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001521
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001522 if (trace->ev_qualifier) {
1523 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1524
1525 if (!(in ^ trace->not_ev_qualifier)) {
1526 sc->filtered = true;
1527 /*
1528 * No need to do read tracepoint information since this will be
1529 * filtered out.
1530 */
1531 return 0;
1532 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001533 }
1534
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001535 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001536
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001537 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001538 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001539
1540 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1541 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001542 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001543 }
1544
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001545 if (sc->tp_format == NULL)
1546 return -1;
1547
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001548 sc->args = sc->tp_format->format.fields;
1549 sc->nr_args = sc->tp_format->format.nr_fields;
1550 /* drop nr field - not relevant here; does not exist on older kernels */
1551 if (sc->args && strcmp(sc->args->name, "nr") == 0) {
1552 sc->args = sc->args->next;
1553 --sc->nr_args;
1554 }
1555
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001556 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1557
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001558 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001559}
1560
David Ahern55d43bc2015-02-19 15:00:22 -05001561/*
1562 * args is to be interpreted as a series of longs but we need to handle
1563 * 8-byte unaligned accesses. args points to raw_data within the event
1564 * and raw_data is guaranteed to be 8-byte unaligned because it is
1565 * preceded by raw_size which is a u32. So we need to copy args to a temp
1566 * variable to read it. Most notably this avoids extended load instructions
1567 * on unaligned addresses
1568 */
1569
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001570static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001571 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001572 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001573{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001574 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001575 unsigned char *p;
1576 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001577
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001578 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001579 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001580 u8 bit = 1;
1581 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001582 .idx = 0,
1583 .mask = 0,
1584 .trace = trace,
1585 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001586 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001587
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001588 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001589 field = field->next, ++arg.idx, bit <<= 1) {
1590 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001591 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001592
1593 /* special care for unaligned accesses */
1594 p = args + sizeof(unsigned long) * arg.idx;
1595 memcpy(&val, p, sizeof(val));
1596
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001597 /*
1598 * Suppress this argument if its value is zero and
1599 * and we don't have a string associated in an
1600 * strarray for it.
1601 */
David Ahern55d43bc2015-02-19 15:00:22 -05001602 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001603 !(sc->arg_scnprintf &&
1604 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1605 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001606 continue;
1607
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001608 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001609 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001610 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001611 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001612 if (sc->arg_parm)
1613 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001614 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1615 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001616 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001617 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001618 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001619 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001620 }
1621 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001622 int i = 0;
1623
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001624 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001625 /* special care for unaligned accesses */
1626 p = args + sizeof(unsigned long) * i;
1627 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001628 printed += scnprintf(bf + printed, size - printed,
1629 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001630 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001631 ++i;
1632 }
1633 }
1634
1635 return printed;
1636}
1637
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001638typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001639 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001640 struct perf_sample *sample);
1641
1642static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001643 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001644{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001645
1646 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001647
1648 /*
1649 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1650 * before that, leaving at a higher verbosity level till that is
1651 * explained. Reproduced with plain ftrace with:
1652 *
1653 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1654 * grep "NR -1 " /t/trace_pipe
1655 *
1656 * After generating some load on the machine.
1657 */
1658 if (verbose > 1) {
1659 static u64 n;
1660 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1661 id, perf_evsel__name(evsel), ++n);
1662 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001663 return NULL;
1664 }
1665
1666 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1667 trace__read_syscall_info(trace, id))
1668 goto out_cant_read;
1669
1670 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1671 goto out_cant_read;
1672
1673 return &trace->syscalls.table[id];
1674
1675out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001676 if (verbose) {
1677 fprintf(trace->output, "Problems reading syscall %d", id);
1678 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1679 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1680 fputs(" information\n", trace->output);
1681 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001682 return NULL;
1683}
1684
David Ahernbf2575c2013-10-08 21:26:53 -06001685static void thread__update_stats(struct thread_trace *ttrace,
1686 int id, struct perf_sample *sample)
1687{
1688 struct int_node *inode;
1689 struct stats *stats;
1690 u64 duration = 0;
1691
1692 inode = intlist__findnew(ttrace->syscall_stats, id);
1693 if (inode == NULL)
1694 return;
1695
1696 stats = inode->priv;
1697 if (stats == NULL) {
1698 stats = malloc(sizeof(struct stats));
1699 if (stats == NULL)
1700 return;
1701 init_stats(stats);
1702 inode->priv = stats;
1703 }
1704
1705 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1706 duration = sample->time - ttrace->entry_time;
1707
1708 update_stats(stats, duration);
1709}
1710
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001711static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1712{
1713 struct thread_trace *ttrace;
1714 u64 duration;
1715 size_t printed;
1716
1717 if (trace->current == NULL)
1718 return 0;
1719
1720 ttrace = thread__priv(trace->current);
1721
1722 if (!ttrace->entry_pending)
1723 return 0;
1724
1725 duration = sample->time - ttrace->entry_time;
1726
1727 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1728 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1729 ttrace->entry_pending = false;
1730
1731 return printed;
1732}
1733
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001734static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001735 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001736 struct perf_sample *sample)
1737{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001738 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001739 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001740 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001741 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001742 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001743 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001744 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001745
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001746 if (sc == NULL)
1747 return -1;
1748
1749 if (sc->filtered)
1750 return 0;
1751
David Ahern8fb598e2013-09-28 13:13:00 -06001752 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001753 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001754 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001755 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001756
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001757 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001758
1759 if (ttrace->entry_str == NULL) {
1760 ttrace->entry_str = malloc(1024);
1761 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001762 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001763 }
1764
David Ahern13f22a22015-03-19 12:23:03 -06001765 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001766 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001767
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001768 ttrace->entry_time = sample->time;
1769 msg = ttrace->entry_str;
1770 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1771
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001772 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1773 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001774
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001775 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001776 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001777 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1778 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001779 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001780 } else
1781 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001782
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001783 if (trace->current != thread) {
1784 thread__put(trace->current);
1785 trace->current = thread__get(thread);
1786 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001787 err = 0;
1788out_put:
1789 thread__put(thread);
1790 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001791}
1792
1793static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001794 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001795 struct perf_sample *sample)
1796{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001797 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001798 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001799 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001800 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001801 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001802 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001803
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001804 if (sc == NULL)
1805 return -1;
1806
1807 if (sc->filtered)
1808 return 0;
1809
David Ahern8fb598e2013-09-28 13:13:00 -06001810 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001811 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001812 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001813 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001814
David Ahernbf2575c2013-10-08 21:26:53 -06001815 if (trace->summary)
1816 thread__update_stats(ttrace, id, sample);
1817
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001818 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001819
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001820 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1821 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1822 trace->last_vfs_getname = NULL;
1823 ++trace->stats.vfs_getname;
1824 }
1825
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001826 ttrace->exit_time = sample->time;
1827
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001828 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001829 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001830 if (trace__filter_duration(trace, duration))
1831 goto out;
1832 } else if (trace->duration_filter)
1833 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001834
David Ahernfd2eaba2013-11-12 09:31:15 -07001835 if (trace->summary_only)
1836 goto out;
1837
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001838 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001839
1840 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001841 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001842 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001843 fprintf(trace->output, " ... [");
1844 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1845 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001846 }
1847
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001848 if (sc->fmt == NULL) {
1849signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001850 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001851 } else if (ret < 0 && sc->fmt->errmsg) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001852 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001853 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1854 *e = audit_errno_to_name(-ret);
1855
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001856 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001857 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001858 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001859 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001860 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001861 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001862 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001863
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001864 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001865out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001866 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001867 err = 0;
1868out_put:
1869 thread__put(thread);
1870 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001871}
1872
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001873static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001874 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001875 struct perf_sample *sample)
1876{
1877 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1878 return 0;
1879}
1880
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001881static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001882 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001883 struct perf_sample *sample)
1884{
1885 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1886 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001887 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001888 sample->pid,
1889 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001890 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001891
1892 if (ttrace == NULL)
1893 goto out_dump;
1894
1895 ttrace->runtime_ms += runtime_ms;
1896 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001897 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001898 return 0;
1899
1900out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001901 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001902 evsel->name,
1903 perf_evsel__strval(evsel, sample, "comm"),
1904 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1905 runtime,
1906 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001907 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001908 return 0;
1909}
1910
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001911static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1912 union perf_event *event __maybe_unused,
1913 struct perf_sample *sample)
1914{
1915 trace__printf_interrupted_entry(trace, sample);
1916 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001917
1918 if (trace->trace_syscalls)
1919 fprintf(trace->output, "( ): ");
1920
1921 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001922
1923 if (evsel->tp_format) {
1924 event_format__fprintf(evsel->tp_format, sample->cpu,
1925 sample->raw_data, sample->raw_size,
1926 trace->output);
1927 }
1928
1929 fprintf(trace->output, ")\n");
1930 return 0;
1931}
1932
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001933static void print_location(FILE *f, struct perf_sample *sample,
1934 struct addr_location *al,
1935 bool print_dso, bool print_sym)
1936{
1937
1938 if ((verbose || print_dso) && al->map)
1939 fprintf(f, "%s@", al->map->dso->long_name);
1940
1941 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001942 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001943 al->addr - al->sym->start);
1944 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001945 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001946 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001947 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001948}
1949
1950static int trace__pgfault(struct trace *trace,
1951 struct perf_evsel *evsel,
1952 union perf_event *event,
1953 struct perf_sample *sample)
1954{
1955 struct thread *thread;
1956 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1957 struct addr_location al;
1958 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001959 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001960 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001961
1962 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001963 ttrace = thread__trace(thread, trace->output);
1964 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001965 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001966
1967 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1968 ttrace->pfmaj++;
1969 else
1970 ttrace->pfmin++;
1971
1972 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001973 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001974
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03001975 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001976 sample->ip, &al);
1977
1978 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
1979
1980 fprintf(trace->output, "%sfault [",
1981 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1982 "maj" : "min");
1983
1984 print_location(trace->output, sample, &al, false, true);
1985
1986 fprintf(trace->output, "] => ");
1987
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03001988 thread__find_addr_location(thread, cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001989 sample->addr, &al);
1990
1991 if (!al.map) {
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03001992 thread__find_addr_location(thread, cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001993 MAP__FUNCTION, sample->addr, &al);
1994
1995 if (al.map)
1996 map_type = 'x';
1997 else
1998 map_type = '?';
1999 }
2000
2001 print_location(trace->output, sample, &al, true, false);
2002
2003 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002004out:
2005 err = 0;
2006out_put:
2007 thread__put(thread);
2008 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002009}
2010
David Ahernbdc89662013-08-28 22:29:53 -06002011static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2012{
2013 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2014 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2015 return false;
2016
2017 if (trace->pid_list || trace->tid_list)
2018 return true;
2019
2020 return false;
2021}
2022
David Ahern6810fc92013-08-28 22:29:52 -06002023static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002024 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002025 struct perf_sample *sample,
2026 struct perf_evsel *evsel,
2027 struct machine *machine __maybe_unused)
2028{
2029 struct trace *trace = container_of(tool, struct trace, tool);
2030 int err = 0;
2031
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002032 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002033
David Ahernbdc89662013-08-28 22:29:53 -06002034 if (skip_sample(trace, sample))
2035 return 0;
2036
David Ahern4bb09192013-09-04 12:37:43 -06002037 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06002038 trace->base_time = sample->time;
2039
David Ahern31605652013-12-04 19:41:41 -07002040 if (handler) {
2041 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002042 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002043 }
David Ahern6810fc92013-08-28 22:29:52 -06002044
2045 return err;
2046}
2047
David Ahernbdc89662013-08-28 22:29:53 -06002048static int parse_target_str(struct trace *trace)
2049{
2050 if (trace->opts.target.pid) {
2051 trace->pid_list = intlist__new(trace->opts.target.pid);
2052 if (trace->pid_list == NULL) {
2053 pr_err("Error parsing process id string\n");
2054 return -EINVAL;
2055 }
2056 }
2057
2058 if (trace->opts.target.tid) {
2059 trace->tid_list = intlist__new(trace->opts.target.tid);
2060 if (trace->tid_list == NULL) {
2061 pr_err("Error parsing thread id string\n");
2062 return -EINVAL;
2063 }
2064 }
2065
2066 return 0;
2067}
2068
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002069static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002070{
2071 unsigned int rec_argc, i, j;
2072 const char **rec_argv;
2073 const char * const record_args[] = {
2074 "record",
2075 "-R",
2076 "-m", "1024",
2077 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002078 };
2079
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002080 const char * const sc_args[] = { "-e", };
2081 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2082 const char * const majpf_args[] = { "-e", "major-faults" };
2083 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2084 const char * const minpf_args[] = { "-e", "minor-faults" };
2085 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2086
David Ahern9aca7f12013-12-04 19:41:39 -07002087 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002088 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2089 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002090 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2091
2092 if (rec_argv == NULL)
2093 return -ENOMEM;
2094
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002095 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002096 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002097 rec_argv[j++] = record_args[i];
2098
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002099 if (trace->trace_syscalls) {
2100 for (i = 0; i < sc_args_nr; i++)
2101 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002102
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002103 /* event string may be different for older kernels - e.g., RHEL6 */
2104 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2105 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2106 else if (is_valid_tracepoint("syscalls:sys_enter"))
2107 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2108 else {
2109 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2110 return -1;
2111 }
David Ahern9aca7f12013-12-04 19:41:39 -07002112 }
David Ahern9aca7f12013-12-04 19:41:39 -07002113
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002114 if (trace->trace_pgfaults & TRACE_PFMAJ)
2115 for (i = 0; i < majpf_args_nr; i++)
2116 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002117
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002118 if (trace->trace_pgfaults & TRACE_PFMIN)
2119 for (i = 0; i < minpf_args_nr; i++)
2120 rec_argv[j++] = minpf_args[i];
2121
2122 for (i = 0; i < (unsigned int)argc; i++)
2123 rec_argv[j++] = argv[i];
2124
2125 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002126}
2127
David Ahernbf2575c2013-10-08 21:26:53 -06002128static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2129
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002130static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
2131{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002132 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002133 if (evsel == NULL)
2134 return;
2135
2136 if (perf_evsel__field(evsel, "pathname") == NULL) {
2137 perf_evsel__delete(evsel);
2138 return;
2139 }
2140
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002141 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002142 perf_evlist__add(evlist, evsel);
2143}
2144
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002145static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2146 u64 config)
2147{
2148 struct perf_evsel *evsel;
2149 struct perf_event_attr attr = {
2150 .type = PERF_TYPE_SOFTWARE,
2151 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002152 };
2153
2154 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002155 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002156
2157 event_attr_init(&attr);
2158
2159 evsel = perf_evsel__new(&attr);
2160 if (!evsel)
2161 return -ENOMEM;
2162
2163 evsel->handler = trace__pgfault;
2164 perf_evlist__add(evlist, evsel);
2165
2166 return 0;
2167}
2168
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002169static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2170{
2171 const u32 type = event->header.type;
2172 struct perf_evsel *evsel;
2173
2174 if (!trace->full_time && trace->base_time == 0)
2175 trace->base_time = sample->time;
2176
2177 if (type != PERF_RECORD_SAMPLE) {
2178 trace__process_event(trace, trace->host, event, sample);
2179 return;
2180 }
2181
2182 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2183 if (evsel == NULL) {
2184 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2185 return;
2186 }
2187
2188 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2189 sample->raw_data == NULL) {
2190 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2191 perf_evsel__name(evsel), sample->tid,
2192 sample->cpu, sample->raw_size);
2193 } else {
2194 tracepoint_handler handler = evsel->handler;
2195 handler(trace, evsel, event, sample);
2196 }
2197}
2198
Namhyung Kimf15eb532012-10-05 14:02:16 +09002199static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002200{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002201 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002202 int err = -1, i;
2203 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002204 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002205 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002206
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002207 trace->live = true;
2208
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002209 if (trace->trace_syscalls &&
2210 perf_evlist__add_syscall_newtp(evlist, trace__sys_enter,
2211 trace__sys_exit))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002212 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002213
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002214 if (trace->trace_syscalls)
2215 perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002216
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002217 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002218 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002219 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002220 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002221
2222 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2223 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002224 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002225
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002226 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002227 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2228 trace__sched_stat_runtime))
2229 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002230
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002231 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2232 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002233 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002234 goto out_delete_evlist;
2235 }
2236
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002237 err = trace__symbols_init(trace, evlist);
2238 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002239 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002240 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002241 }
2242
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002243 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002244
Namhyung Kimf15eb532012-10-05 14:02:16 +09002245 signal(SIGCHLD, sig_handler);
2246 signal(SIGINT, sig_handler);
2247
2248 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002249 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002250 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002251 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002252 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002253 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002254 }
2255 }
2256
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002257 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002258 if (err < 0)
2259 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002260
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002261 /*
2262 * Better not use !target__has_task() here because we need to cover the
2263 * case where no threads were specified in the command line, but a
2264 * workload was, and in that case we will fill in the thread_map when
2265 * we fork the workload in perf_evlist__prepare_workload.
2266 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002267 if (trace->filter_pids.nr > 0)
2268 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
2269 else if (evlist->threads->map[0] == -1)
2270 err = perf_evlist__set_filter_pid(evlist, getpid());
2271
2272 if (err < 0) {
2273 printf("err=%d,%s\n", -err, strerror(-err));
2274 exit(1);
2275 }
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002276
Jiri Olsaf8850372013-11-28 17:57:22 +01002277 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002278 if (err < 0)
2279 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002280
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002281 if (!target__none(&trace->opts.target))
2282 perf_evlist__enable(evlist);
2283
Namhyung Kimf15eb532012-10-05 14:02:16 +09002284 if (forks)
2285 perf_evlist__start_workload(evlist);
2286
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002287 trace->multiple_threads = evlist->threads->map[0] == -1 ||
2288 evlist->threads->nr > 1 ||
2289 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002290again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002291 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002292
2293 for (i = 0; i < evlist->nr_mmaps; i++) {
2294 union perf_event *event;
2295
2296 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002297 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002298
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002299 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002300
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002301 err = perf_evlist__parse_sample(evlist, event, &sample);
2302 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002303 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002304 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002305 }
2306
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002307 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002308next_event:
2309 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002310
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002311 if (interrupted)
2312 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002313
2314 if (done && !draining) {
2315 perf_evlist__disable(evlist);
2316 draining = true;
2317 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002318 }
2319 }
2320
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002321 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002322 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002323
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002324 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2325 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2326 draining = true;
2327
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002328 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002329 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002330 } else {
2331 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002332 }
2333
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002334out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002335 thread__zput(trace->current);
2336
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002337 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002338
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002339 if (!err) {
2340 if (trace->summary)
2341 trace__fprintf_thread_summary(trace, trace->output);
2342
2343 if (trace->show_tool_stats) {
2344 fprintf(trace->output, "Stats:\n "
2345 " vfs_getname : %" PRIu64 "\n"
2346 " proc_getname: %" PRIu64 "\n",
2347 trace->stats.vfs_getname,
2348 trace->stats.proc_getname);
2349 }
2350 }
David Ahernbf2575c2013-10-08 21:26:53 -06002351
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002352out_delete_evlist:
2353 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002354 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002355 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002356 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002357{
2358 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002359
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002360out_error_sched_stat_runtime:
2361 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
2362 goto out_error;
2363
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002364out_error_raw_syscalls:
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002365 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002366 goto out_error;
2367
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002368out_error_mmap:
2369 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2370 goto out_error;
2371
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002372out_error_open:
2373 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2374
2375out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002376 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302377 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002378}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002379out_error_mem:
2380 fprintf(trace->output, "Not enough memory to run!\n");
2381 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002382}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002383
David Ahern6810fc92013-08-28 22:29:52 -06002384static int trace__replay(struct trace *trace)
2385{
2386 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002387 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002388 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002389 struct perf_data_file file = {
2390 .path = input_name,
2391 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002392 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002393 };
David Ahern6810fc92013-08-28 22:29:52 -06002394 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002395 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002396 int err = -1;
2397
2398 trace->tool.sample = trace__process_sample;
2399 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002400 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002401 trace->tool.comm = perf_event__process_comm;
2402 trace->tool.exit = perf_event__process_exit;
2403 trace->tool.fork = perf_event__process_fork;
2404 trace->tool.attr = perf_event__process_attr;
2405 trace->tool.tracing_data = perf_event__process_tracing_data;
2406 trace->tool.build_id = perf_event__process_build_id;
2407
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002408 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002409 trace->tool.ordering_requires_timestamps = true;
2410
2411 /* add tid to output */
2412 trace->multiple_threads = true;
2413
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002414 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002415 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002416 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002417
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002418 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002419 goto out;
2420
David Ahern8fb598e2013-09-28 13:13:00 -06002421 trace->host = &session->machines.host;
2422
David Ahern6810fc92013-08-28 22:29:52 -06002423 err = perf_session__set_tracepoints_handlers(session, handlers);
2424 if (err)
2425 goto out;
2426
Namhyung Kim003824e2013-11-12 15:25:00 +09002427 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2428 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002429 /* older kernels have syscalls tp versus raw_syscalls */
2430 if (evsel == NULL)
2431 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2432 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002433
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002434 if (evsel &&
2435 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2436 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002437 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2438 goto out;
2439 }
2440
2441 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2442 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002443 if (evsel == NULL)
2444 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2445 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002446 if (evsel &&
2447 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2448 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002449 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002450 goto out;
2451 }
2452
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002453 evlist__for_each(session->evlist, evsel) {
2454 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2455 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2456 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2457 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2458 evsel->handler = trace__pgfault;
2459 }
2460
David Ahernbdc89662013-08-28 22:29:53 -06002461 err = parse_target_str(trace);
2462 if (err != 0)
2463 goto out;
2464
David Ahern6810fc92013-08-28 22:29:52 -06002465 setup_pager();
2466
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002467 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002468 if (err)
2469 pr_err("Failed to process events, error %d", err);
2470
David Ahernbf2575c2013-10-08 21:26:53 -06002471 else if (trace->summary)
2472 trace__fprintf_thread_summary(trace, trace->output);
2473
David Ahern6810fc92013-08-28 22:29:52 -06002474out:
2475 perf_session__delete(session);
2476
2477 return err;
2478}
2479
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002480static size_t trace__fprintf_threads_header(FILE *fp)
2481{
2482 size_t printed;
2483
Pekka Enberg99ff7152013-11-12 16:42:14 +02002484 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002485
2486 return printed;
2487}
2488
2489static size_t thread__dump_stats(struct thread_trace *ttrace,
2490 struct trace *trace, FILE *fp)
2491{
2492 struct stats *stats;
2493 size_t printed = 0;
2494 struct syscall *sc;
2495 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2496
2497 if (inode == NULL)
2498 return 0;
2499
2500 printed += fprintf(fp, "\n");
2501
Pekka Enberg27a778b2013-11-13 14:21:48 +02002502 printed += fprintf(fp, " syscall calls min avg max stddev\n");
2503 printed += fprintf(fp, " (msec) (msec) (msec) (%%)\n");
2504 printed += fprintf(fp, " --------------- -------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002505
David Ahernbf2575c2013-10-08 21:26:53 -06002506 /* each int_node is a syscall */
2507 while (inode) {
2508 stats = inode->priv;
2509 if (stats) {
2510 double min = (double)(stats->min) / NSEC_PER_MSEC;
2511 double max = (double)(stats->max) / NSEC_PER_MSEC;
2512 double avg = avg_stats(stats);
2513 double pct;
2514 u64 n = (u64) stats->n;
2515
2516 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2517 avg /= NSEC_PER_MSEC;
2518
2519 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002520 printed += fprintf(fp, " %-15s", sc->name);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002521 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f",
Pekka Enberg7f7a4132013-11-12 16:10:10 +02002522 n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002523 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002524 }
2525
2526 inode = intlist__next(inode);
2527 }
2528
2529 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002530
2531 return printed;
2532}
2533
David Ahern896cbb52013-09-28 13:12:59 -06002534/* struct used to pass data to per-thread function */
2535struct summary_data {
2536 FILE *fp;
2537 struct trace *trace;
2538 size_t printed;
2539};
2540
2541static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2542{
2543 struct summary_data *data = priv;
2544 FILE *fp = data->fp;
2545 size_t printed = data->printed;
2546 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002547 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002548 double ratio;
2549
2550 if (ttrace == NULL)
2551 return 0;
2552
2553 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2554
Pekka Enberg15e65c62013-11-14 18:43:30 +02002555 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002556 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002557 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002558 if (ttrace->pfmaj)
2559 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2560 if (ttrace->pfmin)
2561 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002562 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002563 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002564
2565 data->printed += printed;
2566
2567 return 0;
2568}
2569
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002570static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2571{
David Ahern896cbb52013-09-28 13:12:59 -06002572 struct summary_data data = {
2573 .fp = fp,
2574 .trace = trace
2575 };
2576 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002577
David Ahern896cbb52013-09-28 13:12:59 -06002578 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002579
David Ahern896cbb52013-09-28 13:12:59 -06002580 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002581}
2582
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002583static int trace__set_duration(const struct option *opt, const char *str,
2584 int unset __maybe_unused)
2585{
2586 struct trace *trace = opt->value;
2587
2588 trace->duration_filter = atof(str);
2589 return 0;
2590}
2591
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002592static int trace__set_filter_pids(const struct option *opt, const char *str,
2593 int unset __maybe_unused)
2594{
2595 int ret = -1;
2596 size_t i;
2597 struct trace *trace = opt->value;
2598 /*
2599 * FIXME: introduce a intarray class, plain parse csv and create a
2600 * { int nr, int entries[] } struct...
2601 */
2602 struct intlist *list = intlist__new(str);
2603
2604 if (list == NULL)
2605 return -1;
2606
2607 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2608 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2609
2610 if (trace->filter_pids.entries == NULL)
2611 goto out;
2612
2613 trace->filter_pids.entries[0] = getpid();
2614
2615 for (i = 1; i < trace->filter_pids.nr; ++i)
2616 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2617
2618 intlist__delete(list);
2619 ret = 0;
2620out:
2621 return ret;
2622}
2623
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002624static int trace__open_output(struct trace *trace, const char *filename)
2625{
2626 struct stat st;
2627
2628 if (!stat(filename, &st) && st.st_size) {
2629 char oldname[PATH_MAX];
2630
2631 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2632 unlink(oldname);
2633 rename(filename, oldname);
2634 }
2635
2636 trace->output = fopen(filename, "w");
2637
2638 return trace->output == NULL ? -errno : 0;
2639}
2640
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002641static int parse_pagefaults(const struct option *opt, const char *str,
2642 int unset __maybe_unused)
2643{
2644 int *trace_pgfaults = opt->value;
2645
2646 if (strcmp(str, "all") == 0)
2647 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2648 else if (strcmp(str, "maj") == 0)
2649 *trace_pgfaults |= TRACE_PFMAJ;
2650 else if (strcmp(str, "min") == 0)
2651 *trace_pgfaults |= TRACE_PFMIN;
2652 else
2653 return -1;
2654
2655 return 0;
2656}
2657
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002658static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2659{
2660 struct perf_evsel *evsel;
2661
2662 evlist__for_each(evlist, evsel)
2663 evsel->handler = handler;
2664}
2665
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002666int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2667{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002668 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002669 "perf trace [<options>] [<command>]",
2670 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002671 "perf trace record [<options>] [<command>]",
2672 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002673 NULL
2674 };
2675 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002676 .audit = {
2677 .machine = audit_detect_machine(),
2678 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2679 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002680 .syscalls = {
2681 . max = -1,
2682 },
2683 .opts = {
2684 .target = {
2685 .uid = UINT_MAX,
2686 .uses_mmap = true,
2687 },
2688 .user_freq = UINT_MAX,
2689 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002690 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002691 .mmap_pages = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002692 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002693 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002694 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002695 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002696 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002697 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002698 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002699 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002700 OPT_CALLBACK(0, "event", &trace.evlist, "event",
2701 "event selector. use 'perf list' to list available events",
2702 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002703 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2704 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002705 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03002706 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002707 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002708 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002709 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2710 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002711 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002712 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002713 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2714 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002715 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002716 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002717 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002718 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002719 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002720 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002721 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2722 "number of mmap data pages",
2723 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002724 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002725 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002726 OPT_CALLBACK(0, "duration", &trace, "float",
2727 "show only events with duration > N.M ms",
2728 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002729 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002730 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002731 OPT_BOOLEAN('T', "time", &trace.full_time,
2732 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002733 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2734 "Show only syscall summary with statistics"),
2735 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2736 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002737 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2738 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002739 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002740 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002741 OPT_END()
2742 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002743 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002744 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002745 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002746
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002747 signal(SIGSEGV, sighandler_dump_stack);
2748 signal(SIGFPE, sighandler_dump_stack);
2749
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002750 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002751
2752 if (trace.evlist == NULL) {
2753 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002754 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002755 goto out;
2756 }
2757
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002758 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2759 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002760
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002761 if (trace.trace_pgfaults) {
2762 trace.opts.sample_address = true;
2763 trace.opts.sample_time = true;
2764 }
2765
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002766 if (trace.evlist->nr_entries > 0)
2767 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2768
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002769 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2770 return trace__record(&trace, argc-1, &argv[1]);
2771
2772 /* summary_only implies summary option, but don't overwrite summary if set */
2773 if (trace.summary_only)
2774 trace.summary = trace.summary_only;
2775
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002776 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2777 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002778 pr_err("Please specify something to trace.\n");
2779 return -1;
2780 }
2781
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002782 if (output_name != NULL) {
2783 err = trace__open_output(&trace, output_name);
2784 if (err < 0) {
2785 perror("failed to create output file");
2786 goto out;
2787 }
2788 }
2789
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002790 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002791 const char *s = ev_qualifier_str;
2792
2793 trace.not_ev_qualifier = *s == '!';
2794 if (trace.not_ev_qualifier)
2795 ++s;
2796 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002797 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002798 fputs("Not enough memory to parse event qualifier",
2799 trace.output);
2800 err = -ENOMEM;
2801 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002802 }
2803 }
2804
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002805 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002806 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002807 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002808 fprintf(trace.output, "%s", bf);
2809 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002810 }
2811
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002812 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002813 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002814 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002815 fprintf(trace.output, "%s", bf);
2816 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002817 }
2818
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002819 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002820 trace.opts.target.system_wide = true;
2821
David Ahern6810fc92013-08-28 22:29:52 -06002822 if (input_name)
2823 err = trace__replay(&trace);
2824 else
2825 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002826
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002827out_close:
2828 if (output_name != NULL)
2829 fclose(trace.output);
2830out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002831 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002832}