blob: 431e297b0e3a1677ded4d00dbd5b9c00e1870504 [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 Meloa1c25522015-06-11 22:47:54 -030071#ifndef PERF_FLAG_FD_NO_GROUP
72# define PERF_FLAG_FD_NO_GROUP (1UL << 0)
73#endif
74
75#ifndef PERF_FLAG_FD_OUTPUT
76# define PERF_FLAG_FD_OUTPUT (1UL << 1)
77#endif
78
79#ifndef PERF_FLAG_PID_CGROUP
80# define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */
81#endif
82
83#ifndef PERF_FLAG_FD_CLOEXEC
84# define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */
85#endif
86
87
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -030088struct tp_field {
89 int offset;
90 union {
91 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
92 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
93 };
94};
95
96#define TP_UINT_FIELD(bits) \
97static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
98{ \
David Ahern55d43bc2015-02-19 15:00:22 -050099 u##bits value; \
100 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
101 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300102}
103
104TP_UINT_FIELD(8);
105TP_UINT_FIELD(16);
106TP_UINT_FIELD(32);
107TP_UINT_FIELD(64);
108
109#define TP_UINT_FIELD__SWAPPED(bits) \
110static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
111{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500112 u##bits value; \
113 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300114 return bswap_##bits(value);\
115}
116
117TP_UINT_FIELD__SWAPPED(16);
118TP_UINT_FIELD__SWAPPED(32);
119TP_UINT_FIELD__SWAPPED(64);
120
121static int tp_field__init_uint(struct tp_field *field,
122 struct format_field *format_field,
123 bool needs_swap)
124{
125 field->offset = format_field->offset;
126
127 switch (format_field->size) {
128 case 1:
129 field->integer = tp_field__u8;
130 break;
131 case 2:
132 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
133 break;
134 case 4:
135 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
136 break;
137 case 8:
138 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
139 break;
140 default:
141 return -1;
142 }
143
144 return 0;
145}
146
147static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
148{
149 return sample->raw_data + field->offset;
150}
151
152static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
153{
154 field->offset = format_field->offset;
155 field->pointer = tp_field__ptr;
156 return 0;
157}
158
159struct syscall_tp {
160 struct tp_field id;
161 union {
162 struct tp_field args, ret;
163 };
164};
165
166static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
167 struct tp_field *field,
168 const char *name)
169{
170 struct format_field *format_field = perf_evsel__field(evsel, name);
171
172 if (format_field == NULL)
173 return -1;
174
175 return tp_field__init_uint(field, format_field, evsel->needs_swap);
176}
177
178#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
179 ({ struct syscall_tp *sc = evsel->priv;\
180 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
181
182static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
183 struct tp_field *field,
184 const char *name)
185{
186 struct format_field *format_field = perf_evsel__field(evsel, name);
187
188 if (format_field == NULL)
189 return -1;
190
191 return tp_field__init_ptr(field, format_field);
192}
193
194#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
195 ({ struct syscall_tp *sc = evsel->priv;\
196 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
197
198static void perf_evsel__delete_priv(struct perf_evsel *evsel)
199{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300200 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300201 perf_evsel__delete(evsel);
202}
203
Namhyung Kim96695d42013-11-12 08:51:45 -0300204static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
205{
206 evsel->priv = malloc(sizeof(struct syscall_tp));
207 if (evsel->priv != NULL) {
208 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
209 goto out_delete;
210
211 evsel->handler = handler;
212 return 0;
213 }
214
215 return -ENOMEM;
216
217out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300218 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300219 return -ENOENT;
220}
221
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300222static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300223{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300224 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300225
David Ahern9aca7f12013-12-04 19:41:39 -0700226 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
227 if (evsel == NULL)
228 evsel = perf_evsel__newtp("syscalls", direction);
229
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300230 if (evsel) {
Namhyung Kim96695d42013-11-12 08:51:45 -0300231 if (perf_evsel__init_syscall_tp(evsel, handler))
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300232 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300233 }
234
235 return evsel;
236
237out_delete:
238 perf_evsel__delete_priv(evsel);
239 return NULL;
240}
241
242#define perf_evsel__sc_tp_uint(evsel, name, sample) \
243 ({ struct syscall_tp *fields = evsel->priv; \
244 fields->name.integer(&fields->name, sample); })
245
246#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
247 ({ struct syscall_tp *fields = evsel->priv; \
248 fields->name.pointer(&fields->name, sample); })
249
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300250struct syscall_arg {
251 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300252 struct thread *thread;
253 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300254 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300255 u8 idx;
256 u8 mask;
257};
258
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300259struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300260 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300261 int nr_entries;
262 const char **entries;
263};
264
265#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
266 .nr_entries = ARRAY_SIZE(array), \
267 .entries = array, \
268}
269
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300270#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
271 .offset = off, \
272 .nr_entries = ARRAY_SIZE(array), \
273 .entries = array, \
274}
275
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300276static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
277 const char *intfmt,
278 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300279{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300280 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300281 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300282
283 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300284 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300285
286 return scnprintf(bf, size, "%s", sa->entries[idx]);
287}
288
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300289static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
290 struct syscall_arg *arg)
291{
292 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
293}
294
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300295#define SCA_STRARRAY syscall_arg__scnprintf_strarray
296
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300297#if defined(__i386__) || defined(__x86_64__)
298/*
299 * FIXME: Make this available to all arches as soon as the ioctl beautifier
300 * gets rewritten to support all arches.
301 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300302static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
303 struct syscall_arg *arg)
304{
305 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
306}
307
308#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300309#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300310
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300311static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
312 struct syscall_arg *arg);
313
314#define SCA_FD syscall_arg__scnprintf_fd
315
316static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
317 struct syscall_arg *arg)
318{
319 int fd = arg->val;
320
321 if (fd == AT_FDCWD)
322 return scnprintf(bf, size, "CWD");
323
324 return syscall_arg__scnprintf_fd(bf, size, arg);
325}
326
327#define SCA_FDAT syscall_arg__scnprintf_fd_at
328
329static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
330 struct syscall_arg *arg);
331
332#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
333
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300334static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300335 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300336{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300337 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300338}
339
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300340#define SCA_HEX syscall_arg__scnprintf_hex
341
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300342static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
343 struct syscall_arg *arg)
344{
345 return scnprintf(bf, size, "%d", arg->val);
346}
347
348#define SCA_INT syscall_arg__scnprintf_int
349
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300350static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300351 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300352{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300353 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300354
355 if (prot == PROT_NONE)
356 return scnprintf(bf, size, "NONE");
357#define P_MMAP_PROT(n) \
358 if (prot & PROT_##n) { \
359 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
360 prot &= ~PROT_##n; \
361 }
362
363 P_MMAP_PROT(EXEC);
364 P_MMAP_PROT(READ);
365 P_MMAP_PROT(WRITE);
366#ifdef PROT_SEM
367 P_MMAP_PROT(SEM);
368#endif
369 P_MMAP_PROT(GROWSDOWN);
370 P_MMAP_PROT(GROWSUP);
371#undef P_MMAP_PROT
372
373 if (prot)
374 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
375
376 return printed;
377}
378
379#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
380
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300381static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300382 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300383{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300384 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300385
386#define P_MMAP_FLAG(n) \
387 if (flags & MAP_##n) { \
388 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
389 flags &= ~MAP_##n; \
390 }
391
392 P_MMAP_FLAG(SHARED);
393 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400394#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300395 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400396#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300397 P_MMAP_FLAG(ANONYMOUS);
398 P_MMAP_FLAG(DENYWRITE);
399 P_MMAP_FLAG(EXECUTABLE);
400 P_MMAP_FLAG(FILE);
401 P_MMAP_FLAG(FIXED);
402 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600403#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300404 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600405#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300406 P_MMAP_FLAG(LOCKED);
407 P_MMAP_FLAG(NONBLOCK);
408 P_MMAP_FLAG(NORESERVE);
409 P_MMAP_FLAG(POPULATE);
410 P_MMAP_FLAG(STACK);
411#ifdef MAP_UNINITIALIZED
412 P_MMAP_FLAG(UNINITIALIZED);
413#endif
414#undef P_MMAP_FLAG
415
416 if (flags)
417 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
418
419 return printed;
420}
421
422#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
423
Alex Snast86998dd2014-08-13 18:42:40 +0300424static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
425 struct syscall_arg *arg)
426{
427 int printed = 0, flags = arg->val;
428
429#define P_MREMAP_FLAG(n) \
430 if (flags & MREMAP_##n) { \
431 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
432 flags &= ~MREMAP_##n; \
433 }
434
435 P_MREMAP_FLAG(MAYMOVE);
436#ifdef MREMAP_FIXED
437 P_MREMAP_FLAG(FIXED);
438#endif
439#undef P_MREMAP_FLAG
440
441 if (flags)
442 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
443
444 return printed;
445}
446
447#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
448
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300449static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300450 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300451{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300452 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300453
454 switch (behavior) {
455#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
456 P_MADV_BHV(NORMAL);
457 P_MADV_BHV(RANDOM);
458 P_MADV_BHV(SEQUENTIAL);
459 P_MADV_BHV(WILLNEED);
460 P_MADV_BHV(DONTNEED);
461 P_MADV_BHV(REMOVE);
462 P_MADV_BHV(DONTFORK);
463 P_MADV_BHV(DOFORK);
464 P_MADV_BHV(HWPOISON);
465#ifdef MADV_SOFT_OFFLINE
466 P_MADV_BHV(SOFT_OFFLINE);
467#endif
468 P_MADV_BHV(MERGEABLE);
469 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600470#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300471 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600472#endif
473#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300474 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600475#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300476#ifdef MADV_DONTDUMP
477 P_MADV_BHV(DONTDUMP);
478#endif
479#ifdef MADV_DODUMP
480 P_MADV_BHV(DODUMP);
481#endif
482#undef P_MADV_PHV
483 default: break;
484 }
485
486 return scnprintf(bf, size, "%#x", behavior);
487}
488
489#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
490
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300491static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
492 struct syscall_arg *arg)
493{
494 int printed = 0, op = arg->val;
495
496 if (op == 0)
497 return scnprintf(bf, size, "NONE");
498#define P_CMD(cmd) \
499 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
500 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
501 op &= ~LOCK_##cmd; \
502 }
503
504 P_CMD(SH);
505 P_CMD(EX);
506 P_CMD(NB);
507 P_CMD(UN);
508 P_CMD(MAND);
509 P_CMD(RW);
510 P_CMD(READ);
511 P_CMD(WRITE);
512#undef P_OP
513
514 if (op)
515 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
516
517 return printed;
518}
519
520#define SCA_FLOCK syscall_arg__scnprintf_flock
521
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300522static 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 -0300523{
524 enum syscall_futex_args {
525 SCF_UADDR = (1 << 0),
526 SCF_OP = (1 << 1),
527 SCF_VAL = (1 << 2),
528 SCF_TIMEOUT = (1 << 3),
529 SCF_UADDR2 = (1 << 4),
530 SCF_VAL3 = (1 << 5),
531 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300532 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300533 int cmd = op & FUTEX_CMD_MASK;
534 size_t printed = 0;
535
536 switch (cmd) {
537#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300538 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
539 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
540 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
541 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
542 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
543 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300544 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300545 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
546 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
547 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
548 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
549 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300550 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
551 default: printed = scnprintf(bf, size, "%#x", cmd); break;
552 }
553
554 if (op & FUTEX_PRIVATE_FLAG)
555 printed += scnprintf(bf + printed, size - printed, "|PRIV");
556
557 if (op & FUTEX_CLOCK_REALTIME)
558 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
559
560 return printed;
561}
562
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300563#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
564
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300565static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
566static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300567
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300568static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
569static DEFINE_STRARRAY(itimers);
570
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300571static const char *whences[] = { "SET", "CUR", "END",
572#ifdef SEEK_DATA
573"DATA",
574#endif
575#ifdef SEEK_HOLE
576"HOLE",
577#endif
578};
579static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300580
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300581static const char *fcntl_cmds[] = {
582 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
583 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
584 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
585 "F_GETOWNER_UIDS",
586};
587static DEFINE_STRARRAY(fcntl_cmds);
588
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300589static const char *rlimit_resources[] = {
590 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
591 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
592 "RTTIME",
593};
594static DEFINE_STRARRAY(rlimit_resources);
595
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300596static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
597static DEFINE_STRARRAY(sighow);
598
David Ahern4f8c1b72013-09-22 19:45:00 -0600599static const char *clockid[] = {
600 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
601 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
602};
603static DEFINE_STRARRAY(clockid);
604
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300605static const char *socket_families[] = {
606 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
607 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
608 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
609 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
610 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
611 "ALG", "NFC", "VSOCK",
612};
613static DEFINE_STRARRAY(socket_families);
614
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300615#ifndef SOCK_TYPE_MASK
616#define SOCK_TYPE_MASK 0xf
617#endif
618
619static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
620 struct syscall_arg *arg)
621{
622 size_t printed;
623 int type = arg->val,
624 flags = type & ~SOCK_TYPE_MASK;
625
626 type &= SOCK_TYPE_MASK;
627 /*
628 * Can't use a strarray, MIPS may override for ABI reasons.
629 */
630 switch (type) {
631#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
632 P_SK_TYPE(STREAM);
633 P_SK_TYPE(DGRAM);
634 P_SK_TYPE(RAW);
635 P_SK_TYPE(RDM);
636 P_SK_TYPE(SEQPACKET);
637 P_SK_TYPE(DCCP);
638 P_SK_TYPE(PACKET);
639#undef P_SK_TYPE
640 default:
641 printed = scnprintf(bf, size, "%#x", type);
642 }
643
644#define P_SK_FLAG(n) \
645 if (flags & SOCK_##n) { \
646 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
647 flags &= ~SOCK_##n; \
648 }
649
650 P_SK_FLAG(CLOEXEC);
651 P_SK_FLAG(NONBLOCK);
652#undef P_SK_FLAG
653
654 if (flags)
655 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
656
657 return printed;
658}
659
660#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
661
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300662#ifndef MSG_PROBE
663#define MSG_PROBE 0x10
664#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600665#ifndef MSG_WAITFORONE
666#define MSG_WAITFORONE 0x10000
667#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300668#ifndef MSG_SENDPAGE_NOTLAST
669#define MSG_SENDPAGE_NOTLAST 0x20000
670#endif
671#ifndef MSG_FASTOPEN
672#define MSG_FASTOPEN 0x20000000
673#endif
674
675static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
676 struct syscall_arg *arg)
677{
678 int printed = 0, flags = arg->val;
679
680 if (flags == 0)
681 return scnprintf(bf, size, "NONE");
682#define P_MSG_FLAG(n) \
683 if (flags & MSG_##n) { \
684 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
685 flags &= ~MSG_##n; \
686 }
687
688 P_MSG_FLAG(OOB);
689 P_MSG_FLAG(PEEK);
690 P_MSG_FLAG(DONTROUTE);
691 P_MSG_FLAG(TRYHARD);
692 P_MSG_FLAG(CTRUNC);
693 P_MSG_FLAG(PROBE);
694 P_MSG_FLAG(TRUNC);
695 P_MSG_FLAG(DONTWAIT);
696 P_MSG_FLAG(EOR);
697 P_MSG_FLAG(WAITALL);
698 P_MSG_FLAG(FIN);
699 P_MSG_FLAG(SYN);
700 P_MSG_FLAG(CONFIRM);
701 P_MSG_FLAG(RST);
702 P_MSG_FLAG(ERRQUEUE);
703 P_MSG_FLAG(NOSIGNAL);
704 P_MSG_FLAG(MORE);
705 P_MSG_FLAG(WAITFORONE);
706 P_MSG_FLAG(SENDPAGE_NOTLAST);
707 P_MSG_FLAG(FASTOPEN);
708 P_MSG_FLAG(CMSG_CLOEXEC);
709#undef P_MSG_FLAG
710
711 if (flags)
712 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
713
714 return printed;
715}
716
717#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
718
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300719static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
720 struct syscall_arg *arg)
721{
722 size_t printed = 0;
723 int mode = arg->val;
724
725 if (mode == F_OK) /* 0 */
726 return scnprintf(bf, size, "F");
727#define P_MODE(n) \
728 if (mode & n##_OK) { \
729 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
730 mode &= ~n##_OK; \
731 }
732
733 P_MODE(R);
734 P_MODE(W);
735 P_MODE(X);
736#undef P_MODE
737
738 if (mode)
739 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
740
741 return printed;
742}
743
744#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
745
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300746static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300747 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300748{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300749 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300750
751 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300752 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300753
754 if (flags == 0)
755 return scnprintf(bf, size, "RDONLY");
756#define P_FLAG(n) \
757 if (flags & O_##n) { \
758 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
759 flags &= ~O_##n; \
760 }
761
762 P_FLAG(APPEND);
763 P_FLAG(ASYNC);
764 P_FLAG(CLOEXEC);
765 P_FLAG(CREAT);
766 P_FLAG(DIRECT);
767 P_FLAG(DIRECTORY);
768 P_FLAG(EXCL);
769 P_FLAG(LARGEFILE);
770 P_FLAG(NOATIME);
771 P_FLAG(NOCTTY);
772#ifdef O_NONBLOCK
773 P_FLAG(NONBLOCK);
774#elif O_NDELAY
775 P_FLAG(NDELAY);
776#endif
777#ifdef O_PATH
778 P_FLAG(PATH);
779#endif
780 P_FLAG(RDWR);
781#ifdef O_DSYNC
782 if ((flags & O_SYNC) == O_SYNC)
783 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
784 else {
785 P_FLAG(DSYNC);
786 }
787#else
788 P_FLAG(SYNC);
789#endif
790 P_FLAG(TRUNC);
791 P_FLAG(WRONLY);
792#undef P_FLAG
793
794 if (flags)
795 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
796
797 return printed;
798}
799
800#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
801
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300802static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size,
803 struct syscall_arg *arg)
804{
805 int printed = 0, flags = arg->val;
806
807 if (flags == 0)
808 return 0;
809
810#define P_FLAG(n) \
811 if (flags & PERF_FLAG_##n) { \
812 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
813 flags &= ~PERF_FLAG_##n; \
814 }
815
816 P_FLAG(FD_NO_GROUP);
817 P_FLAG(FD_OUTPUT);
818 P_FLAG(PID_CGROUP);
819 P_FLAG(FD_CLOEXEC);
820#undef P_FLAG
821
822 if (flags)
823 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
824
825 return printed;
826}
827
828#define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags
829
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300830static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
831 struct syscall_arg *arg)
832{
833 int printed = 0, flags = arg->val;
834
835 if (flags == 0)
836 return scnprintf(bf, size, "NONE");
837#define P_FLAG(n) \
838 if (flags & EFD_##n) { \
839 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
840 flags &= ~EFD_##n; \
841 }
842
843 P_FLAG(SEMAPHORE);
844 P_FLAG(CLOEXEC);
845 P_FLAG(NONBLOCK);
846#undef P_FLAG
847
848 if (flags)
849 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
850
851 return printed;
852}
853
854#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
855
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300856static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
857 struct syscall_arg *arg)
858{
859 int printed = 0, flags = arg->val;
860
861#define P_FLAG(n) \
862 if (flags & O_##n) { \
863 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
864 flags &= ~O_##n; \
865 }
866
867 P_FLAG(CLOEXEC);
868 P_FLAG(NONBLOCK);
869#undef P_FLAG
870
871 if (flags)
872 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
873
874 return printed;
875}
876
877#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
878
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300879static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
880{
881 int sig = arg->val;
882
883 switch (sig) {
884#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
885 P_SIGNUM(HUP);
886 P_SIGNUM(INT);
887 P_SIGNUM(QUIT);
888 P_SIGNUM(ILL);
889 P_SIGNUM(TRAP);
890 P_SIGNUM(ABRT);
891 P_SIGNUM(BUS);
892 P_SIGNUM(FPE);
893 P_SIGNUM(KILL);
894 P_SIGNUM(USR1);
895 P_SIGNUM(SEGV);
896 P_SIGNUM(USR2);
897 P_SIGNUM(PIPE);
898 P_SIGNUM(ALRM);
899 P_SIGNUM(TERM);
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300900 P_SIGNUM(CHLD);
901 P_SIGNUM(CONT);
902 P_SIGNUM(STOP);
903 P_SIGNUM(TSTP);
904 P_SIGNUM(TTIN);
905 P_SIGNUM(TTOU);
906 P_SIGNUM(URG);
907 P_SIGNUM(XCPU);
908 P_SIGNUM(XFSZ);
909 P_SIGNUM(VTALRM);
910 P_SIGNUM(PROF);
911 P_SIGNUM(WINCH);
912 P_SIGNUM(IO);
913 P_SIGNUM(PWR);
914 P_SIGNUM(SYS);
Ben Hutchings02c5bb42014-02-06 01:00:41 +0000915#ifdef SIGEMT
916 P_SIGNUM(EMT);
917#endif
918#ifdef SIGSTKFLT
919 P_SIGNUM(STKFLT);
920#endif
921#ifdef SIGSWI
922 P_SIGNUM(SWI);
923#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300924 default: break;
925 }
926
927 return scnprintf(bf, size, "%#x", sig);
928}
929
930#define SCA_SIGNUM syscall_arg__scnprintf_signum
931
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300932#if defined(__i386__) || defined(__x86_64__)
933/*
934 * FIXME: Make this available to all arches.
935 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300936#define TCGETS 0x5401
937
938static const char *tioctls[] = {
939 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
940 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
941 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
942 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
943 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
944 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
945 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
946 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
947 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
948 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
949 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
950 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
951 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
952 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
953 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
954};
955
956static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300957#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300958
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300959#define STRARRAY(arg, name, array) \
960 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
961 .arg_parm = { [arg] = &strarray__##array, }
962
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300963static struct syscall_fmt {
964 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300965 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300966 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300967 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300968 bool errmsg;
969 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300970 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300971} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300972 { .name = "access", .errmsg = true,
973 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300974 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300975 { .name = "brk", .hexret = true,
976 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600977 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300978 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300979 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300980 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300981 { .name = "dup", .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 = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300984 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300985 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300986 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300987 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300988 { .name = "eventfd2", .errmsg = true,
989 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300990 { .name = "faccessat", .errmsg = true,
991 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
992 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300993 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300994 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300995 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300996 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300997 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300998 { .name = "fchmod", .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 = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001001 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001002 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001003 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001004 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001005 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001006 { .name = "fcntl", .errmsg = true,
1007 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1008 [1] = SCA_STRARRAY, /* cmd */ },
1009 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1010 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001011 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -03001012 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001013 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1014 [1] = SCA_FLOCK, /* cmd */ }, },
1015 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001016 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001017 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001018 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001019 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001020 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001021 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001022 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001023 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001024 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001025 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001026 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -03001027 { .name = "futex", .errmsg = true,
1028 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001029 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001030 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001031 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001032 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001033 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001034 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001035 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1036 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001037 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001038 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001039#if defined(__i386__) || defined(__x86_64__)
1040/*
1041 * FIXME: Make this available to all arches.
1042 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001043 [1] = SCA_STRHEXARRAY, /* cmd */
1044 [2] = SCA_HEX, /* arg */ },
1045 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001046#else
1047 [2] = SCA_HEX, /* arg */ }, },
1048#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001049 { .name = "kill", .errmsg = true,
1050 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001051 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001052 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001053 { .name = "lseek", .errmsg = true,
1054 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1055 [2] = SCA_STRARRAY, /* whence */ },
1056 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001057 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001058 { .name = "madvise", .errmsg = true,
1059 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1060 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001061 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001062 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001063 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001064 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001065 { .name = "mlock", .errmsg = true,
1066 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1067 { .name = "mlockall", .errmsg = true,
1068 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001069 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001070 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001071 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001072 [3] = SCA_MMAP_FLAGS, /* flags */
1073 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001074 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001075 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1076 [2] = SCA_MMAP_PROT, /* prot */ }, },
1077 { .name = "mremap", .hexret = true,
1078 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001079 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001080 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001081 { .name = "munlock", .errmsg = true,
1082 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001083 { .name = "munmap", .errmsg = true,
1084 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001085 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001086 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001087 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001088 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001089 { .name = "open", .errmsg = true,
1090 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001091 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001092 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1093 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001094 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001095 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1096 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001097 { .name = "perf_event_open", .errmsg = true,
1098 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1099 [2] = SCA_INT, /* cpu */
1100 [3] = SCA_FD, /* group_fd */
1101 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001102 { .name = "pipe2", .errmsg = true,
1103 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001104 { .name = "poll", .errmsg = true, .timeout = true, },
1105 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001106 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001107 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001108 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001109 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001110 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001111 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001112 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001113 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001114 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001115 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001116 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001117 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001118 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001119 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001120 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001121 { .name = "recvfrom", .errmsg = true,
1122 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1123 { .name = "recvmmsg", .errmsg = true,
1124 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1125 { .name = "recvmsg", .errmsg = true,
1126 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001127 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001128 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001129 { .name = "rt_sigaction", .errmsg = true,
1130 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001131 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001132 { .name = "rt_sigqueueinfo", .errmsg = true,
1133 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1134 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1135 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001136 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001137 { .name = "sendmmsg", .errmsg = true,
1138 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1139 { .name = "sendmsg", .errmsg = true,
1140 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
1141 { .name = "sendto", .errmsg = true,
1142 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001143 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1144 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001145 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001146 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001147 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001148 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1149 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001150 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001151 { .name = "socketpair", .errmsg = true,
1152 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1153 [1] = SCA_SK_TYPE, /* type */ },
1154 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001155 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001156 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001157 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001158 { .name = "tgkill", .errmsg = true,
1159 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1160 { .name = "tkill", .errmsg = true,
1161 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001162 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001163 { .name = "unlinkat", .errmsg = true,
1164 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1165 { .name = "utimensat", .errmsg = true,
1166 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
1167 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001168 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001169 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001170 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001171};
1172
1173static int syscall_fmt__cmp(const void *name, const void *fmtp)
1174{
1175 const struct syscall_fmt *fmt = fmtp;
1176 return strcmp(name, fmt->name);
1177}
1178
1179static struct syscall_fmt *syscall_fmt__find(const char *name)
1180{
1181 const int nmemb = ARRAY_SIZE(syscall_fmts);
1182 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1183}
1184
1185struct syscall {
1186 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001187 int nr_args;
1188 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001189 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001190 bool filtered;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001191 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001192 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001193 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001194 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001195};
1196
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001197static size_t fprintf_duration(unsigned long t, FILE *fp)
1198{
1199 double duration = (double)t / NSEC_PER_MSEC;
1200 size_t printed = fprintf(fp, "(");
1201
1202 if (duration >= 1.0)
1203 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1204 else if (duration >= 0.01)
1205 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1206 else
1207 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001208 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001209}
1210
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001211struct thread_trace {
1212 u64 entry_time;
1213 u64 exit_time;
1214 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001215 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001216 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001217 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001218 double runtime_ms;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001219 struct {
1220 int max;
1221 char **table;
1222 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001223
1224 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001225};
1226
1227static struct thread_trace *thread_trace__new(void)
1228{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001229 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1230
1231 if (ttrace)
1232 ttrace->paths.max = -1;
1233
David Ahernbf2575c2013-10-08 21:26:53 -06001234 ttrace->syscall_stats = intlist__new(NULL);
1235
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001236 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001237}
1238
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001239static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001240{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001241 struct thread_trace *ttrace;
1242
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001243 if (thread == NULL)
1244 goto fail;
1245
Namhyung Kim89dceb22014-10-06 09:46:03 +09001246 if (thread__priv(thread) == NULL)
1247 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001248
Namhyung Kim89dceb22014-10-06 09:46:03 +09001249 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001250 goto fail;
1251
Namhyung Kim89dceb22014-10-06 09:46:03 +09001252 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001253 ++ttrace->nr_events;
1254
1255 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001256fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001257 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001258 "WARNING: not enough memory, dropping samples!\n");
1259 return NULL;
1260}
1261
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001262#define TRACE_PFMAJ (1 << 0)
1263#define TRACE_PFMIN (1 << 1)
1264
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001265struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001266 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001267 struct {
1268 int machine;
1269 int open_id;
1270 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001271 struct {
1272 int max;
1273 struct syscall *table;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001274 struct {
1275 struct perf_evsel *enter,
1276 *exit;
1277 } events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001278 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001279 struct record_opts opts;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001280 struct perf_evlist *evlist;
David Ahern8fb598e2013-09-28 13:13:00 -06001281 struct machine *host;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001282 struct thread *current;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001283 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001284 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001285 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001286 struct strlist *ev_qualifier;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001287 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -06001288 struct intlist *tid_list;
1289 struct intlist *pid_list;
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08001290 struct {
1291 size_t nr;
1292 pid_t *entries;
1293 } filter_pids;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001294 double duration_filter;
1295 double runtime_ms;
1296 struct {
1297 u64 vfs_getname,
1298 proc_getname;
1299 } stats;
1300 bool not_ev_qualifier;
1301 bool live;
1302 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001303 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001304 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001305 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001306 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001307 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001308 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001309 bool trace_syscalls;
Yunlong Songe366a6d2015-04-02 21:47:18 +08001310 bool force;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001311 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001312};
1313
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001314static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001315{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001316 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001317
1318 if (fd > ttrace->paths.max) {
1319 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1320
1321 if (npath == NULL)
1322 return -1;
1323
1324 if (ttrace->paths.max != -1) {
1325 memset(npath + ttrace->paths.max + 1, 0,
1326 (fd - ttrace->paths.max) * sizeof(char *));
1327 } else {
1328 memset(npath, 0, (fd + 1) * sizeof(char *));
1329 }
1330
1331 ttrace->paths.table = npath;
1332 ttrace->paths.max = fd;
1333 }
1334
1335 ttrace->paths.table[fd] = strdup(pathname);
1336
1337 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1338}
1339
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001340static int thread__read_fd_path(struct thread *thread, int fd)
1341{
1342 char linkname[PATH_MAX], pathname[PATH_MAX];
1343 struct stat st;
1344 int ret;
1345
1346 if (thread->pid_ == thread->tid) {
1347 scnprintf(linkname, sizeof(linkname),
1348 "/proc/%d/fd/%d", thread->pid_, fd);
1349 } else {
1350 scnprintf(linkname, sizeof(linkname),
1351 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1352 }
1353
1354 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1355 return -1;
1356
1357 ret = readlink(linkname, pathname, sizeof(pathname));
1358
1359 if (ret < 0 || ret > st.st_size)
1360 return -1;
1361
1362 pathname[ret] = '\0';
1363 return trace__set_fd_pathname(thread, fd, pathname);
1364}
1365
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001366static const char *thread__fd_path(struct thread *thread, int fd,
1367 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001368{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001369 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001370
1371 if (ttrace == NULL)
1372 return NULL;
1373
1374 if (fd < 0)
1375 return NULL;
1376
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001377 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001378 if (!trace->live)
1379 return NULL;
1380 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001381 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001382 return NULL;
1383 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001384
1385 return ttrace->paths.table[fd];
1386}
1387
1388static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1389 struct syscall_arg *arg)
1390{
1391 int fd = arg->val;
1392 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001393 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001394
1395 if (path)
1396 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1397
1398 return printed;
1399}
1400
1401static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1402 struct syscall_arg *arg)
1403{
1404 int fd = arg->val;
1405 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001406 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001407
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001408 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1409 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001410
1411 return printed;
1412}
1413
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001414static bool trace__filter_duration(struct trace *trace, double t)
1415{
1416 return t < (trace->duration_filter * NSEC_PER_MSEC);
1417}
1418
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001419static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1420{
1421 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1422
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001423 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001424}
1425
Namhyung Kimf15eb532012-10-05 14:02:16 +09001426static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001427static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001428
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001429static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001430{
1431 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001432 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001433}
1434
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001435static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001436 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001437{
1438 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001439 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001440
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001441 if (trace->multiple_threads) {
1442 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001443 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001444 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001445 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001446
1447 return printed;
1448}
1449
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001450static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001451 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001452{
1453 int ret = 0;
1454
1455 switch (event->header.type) {
1456 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001457 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001458 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001459 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001460 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001461 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001462 break;
1463 }
1464
1465 return ret;
1466}
1467
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001468static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001469 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001470 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001471 struct machine *machine)
1472{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001473 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001474 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001475}
1476
1477static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1478{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001479 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001480
1481 if (err)
1482 return err;
1483
David Ahern8fb598e2013-09-28 13:13:00 -06001484 trace->host = machine__new_host();
1485 if (trace->host == NULL)
1486 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001487
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001488 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001489 evlist->threads, trace__tool_process, false,
1490 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001491 if (err)
1492 symbol__exit();
1493
1494 return err;
1495}
1496
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001497static int syscall__set_arg_fmts(struct syscall *sc)
1498{
1499 struct format_field *field;
1500 int idx = 0;
1501
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001502 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001503 if (sc->arg_scnprintf == NULL)
1504 return -1;
1505
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001506 if (sc->fmt)
1507 sc->arg_parm = sc->fmt->arg_parm;
1508
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001509 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001510 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1511 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1512 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001513 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1514 ++idx;
1515 }
1516
1517 return 0;
1518}
1519
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001520static int trace__read_syscall_info(struct trace *trace, int id)
1521{
1522 char tp_name[128];
1523 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001524 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001525
1526 if (name == NULL)
1527 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001528
1529 if (id > trace->syscalls.max) {
1530 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1531
1532 if (nsyscalls == NULL)
1533 return -1;
1534
1535 if (trace->syscalls.max != -1) {
1536 memset(nsyscalls + trace->syscalls.max + 1, 0,
1537 (id - trace->syscalls.max) * sizeof(*sc));
1538 } else {
1539 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1540 }
1541
1542 trace->syscalls.table = nsyscalls;
1543 trace->syscalls.max = id;
1544 }
1545
1546 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001547 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001548
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001549 if (trace->ev_qualifier) {
1550 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1551
1552 if (!(in ^ trace->not_ev_qualifier)) {
1553 sc->filtered = true;
1554 /*
1555 * No need to do read tracepoint information since this will be
1556 * filtered out.
1557 */
1558 return 0;
1559 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001560 }
1561
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001562 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001563
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001564 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001565 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001566
1567 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1568 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001569 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001570 }
1571
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001572 if (sc->tp_format == NULL)
1573 return -1;
1574
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001575 sc->args = sc->tp_format->format.fields;
1576 sc->nr_args = sc->tp_format->format.nr_fields;
1577 /* drop nr field - not relevant here; does not exist on older kernels */
1578 if (sc->args && strcmp(sc->args->name, "nr") == 0) {
1579 sc->args = sc->args->next;
1580 --sc->nr_args;
1581 }
1582
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001583 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1584
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001585 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001586}
1587
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001588static int trace__validate_ev_qualifier(struct trace *trace)
1589{
1590 int err = 0;
1591 struct str_node *pos;
1592
1593 strlist__for_each(pos, trace->ev_qualifier) {
1594 const char *sc = pos->s;
1595
1596 if (audit_name_to_syscall(sc, trace->audit.machine) < 0) {
1597 if (err == 0) {
1598 fputs("Error:\tInvalid syscall ", trace->output);
1599 err = -EINVAL;
1600 } else {
1601 fputs(", ", trace->output);
1602 }
1603
1604 fputs(sc, trace->output);
1605 }
1606 }
1607
1608 if (err < 0) {
1609 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1610 "\nHint:\tand: 'man syscalls'\n", trace->output);
1611 }
1612
1613 return err;
1614}
1615
David Ahern55d43bc2015-02-19 15:00:22 -05001616/*
1617 * args is to be interpreted as a series of longs but we need to handle
1618 * 8-byte unaligned accesses. args points to raw_data within the event
1619 * and raw_data is guaranteed to be 8-byte unaligned because it is
1620 * preceded by raw_size which is a u32. So we need to copy args to a temp
1621 * variable to read it. Most notably this avoids extended load instructions
1622 * on unaligned addresses
1623 */
1624
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001625static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001626 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001627 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001628{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001629 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001630 unsigned char *p;
1631 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001632
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001633 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001634 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001635 u8 bit = 1;
1636 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001637 .idx = 0,
1638 .mask = 0,
1639 .trace = trace,
1640 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001641 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001642
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001643 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001644 field = field->next, ++arg.idx, bit <<= 1) {
1645 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001646 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001647
1648 /* special care for unaligned accesses */
1649 p = args + sizeof(unsigned long) * arg.idx;
1650 memcpy(&val, p, sizeof(val));
1651
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001652 /*
1653 * Suppress this argument if its value is zero and
1654 * and we don't have a string associated in an
1655 * strarray for it.
1656 */
David Ahern55d43bc2015-02-19 15:00:22 -05001657 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001658 !(sc->arg_scnprintf &&
1659 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1660 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001661 continue;
1662
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001663 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001664 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001665 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001666 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001667 if (sc->arg_parm)
1668 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001669 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1670 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001671 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001672 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001673 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001674 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001675 }
1676 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001677 int i = 0;
1678
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001679 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001680 /* special care for unaligned accesses */
1681 p = args + sizeof(unsigned long) * i;
1682 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001683 printed += scnprintf(bf + printed, size - printed,
1684 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001685 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001686 ++i;
1687 }
1688 }
1689
1690 return printed;
1691}
1692
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001693typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001694 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001695 struct perf_sample *sample);
1696
1697static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001698 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001699{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001700
1701 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001702
1703 /*
1704 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1705 * before that, leaving at a higher verbosity level till that is
1706 * explained. Reproduced with plain ftrace with:
1707 *
1708 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1709 * grep "NR -1 " /t/trace_pipe
1710 *
1711 * After generating some load on the machine.
1712 */
1713 if (verbose > 1) {
1714 static u64 n;
1715 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1716 id, perf_evsel__name(evsel), ++n);
1717 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001718 return NULL;
1719 }
1720
1721 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1722 trace__read_syscall_info(trace, id))
1723 goto out_cant_read;
1724
1725 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1726 goto out_cant_read;
1727
1728 return &trace->syscalls.table[id];
1729
1730out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001731 if (verbose) {
1732 fprintf(trace->output, "Problems reading syscall %d", id);
1733 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1734 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1735 fputs(" information\n", trace->output);
1736 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001737 return NULL;
1738}
1739
David Ahernbf2575c2013-10-08 21:26:53 -06001740static void thread__update_stats(struct thread_trace *ttrace,
1741 int id, struct perf_sample *sample)
1742{
1743 struct int_node *inode;
1744 struct stats *stats;
1745 u64 duration = 0;
1746
1747 inode = intlist__findnew(ttrace->syscall_stats, id);
1748 if (inode == NULL)
1749 return;
1750
1751 stats = inode->priv;
1752 if (stats == NULL) {
1753 stats = malloc(sizeof(struct stats));
1754 if (stats == NULL)
1755 return;
1756 init_stats(stats);
1757 inode->priv = stats;
1758 }
1759
1760 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1761 duration = sample->time - ttrace->entry_time;
1762
1763 update_stats(stats, duration);
1764}
1765
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001766static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1767{
1768 struct thread_trace *ttrace;
1769 u64 duration;
1770 size_t printed;
1771
1772 if (trace->current == NULL)
1773 return 0;
1774
1775 ttrace = thread__priv(trace->current);
1776
1777 if (!ttrace->entry_pending)
1778 return 0;
1779
1780 duration = sample->time - ttrace->entry_time;
1781
1782 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1783 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1784 ttrace->entry_pending = false;
1785
1786 return printed;
1787}
1788
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001789static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001790 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001791 struct perf_sample *sample)
1792{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001793 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001794 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001795 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001796 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001797 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001798 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001799 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001800
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001801 if (sc == NULL)
1802 return -1;
1803
1804 if (sc->filtered)
1805 return 0;
1806
David Ahern8fb598e2013-09-28 13:13:00 -06001807 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001808 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001809 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001810 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001811
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001812 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001813
1814 if (ttrace->entry_str == NULL) {
1815 ttrace->entry_str = malloc(1024);
1816 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001817 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001818 }
1819
David Ahern13f22a22015-03-19 12:23:03 -06001820 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001821 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001822
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001823 ttrace->entry_time = sample->time;
1824 msg = ttrace->entry_str;
1825 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1826
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001827 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1828 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001829
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001830 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001831 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001832 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1833 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001834 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001835 } else
1836 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001837
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001838 if (trace->current != thread) {
1839 thread__put(trace->current);
1840 trace->current = thread__get(thread);
1841 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001842 err = 0;
1843out_put:
1844 thread__put(thread);
1845 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001846}
1847
1848static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001849 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001850 struct perf_sample *sample)
1851{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001852 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001853 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001854 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001855 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001856 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001857 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001858
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001859 if (sc == NULL)
1860 return -1;
1861
1862 if (sc->filtered)
1863 return 0;
1864
David Ahern8fb598e2013-09-28 13:13:00 -06001865 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001866 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001867 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001868 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001869
David Ahernbf2575c2013-10-08 21:26:53 -06001870 if (trace->summary)
1871 thread__update_stats(ttrace, id, sample);
1872
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001873 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001874
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001875 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1876 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1877 trace->last_vfs_getname = NULL;
1878 ++trace->stats.vfs_getname;
1879 }
1880
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001881 ttrace->exit_time = sample->time;
1882
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001883 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001884 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001885 if (trace__filter_duration(trace, duration))
1886 goto out;
1887 } else if (trace->duration_filter)
1888 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001889
David Ahernfd2eaba2013-11-12 09:31:15 -07001890 if (trace->summary_only)
1891 goto out;
1892
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001893 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001894
1895 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001896 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001897 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001898 fprintf(trace->output, " ... [");
1899 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1900 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001901 }
1902
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001903 if (sc->fmt == NULL) {
1904signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001905 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001906 } else if (ret < 0 && sc->fmt->errmsg) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001907 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001908 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1909 *e = audit_errno_to_name(-ret);
1910
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001911 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001912 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001913 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001914 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001915 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001916 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001917 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001918
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001919 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001920out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001921 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001922 err = 0;
1923out_put:
1924 thread__put(thread);
1925 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001926}
1927
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001928static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001929 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001930 struct perf_sample *sample)
1931{
1932 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1933 return 0;
1934}
1935
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001936static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001937 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001938 struct perf_sample *sample)
1939{
1940 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1941 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001942 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001943 sample->pid,
1944 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001945 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001946
1947 if (ttrace == NULL)
1948 goto out_dump;
1949
1950 ttrace->runtime_ms += runtime_ms;
1951 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001952 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001953 return 0;
1954
1955out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001956 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001957 evsel->name,
1958 perf_evsel__strval(evsel, sample, "comm"),
1959 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1960 runtime,
1961 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001962 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001963 return 0;
1964}
1965
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001966static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1967 union perf_event *event __maybe_unused,
1968 struct perf_sample *sample)
1969{
1970 trace__printf_interrupted_entry(trace, sample);
1971 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001972
1973 if (trace->trace_syscalls)
1974 fprintf(trace->output, "( ): ");
1975
1976 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001977
1978 if (evsel->tp_format) {
1979 event_format__fprintf(evsel->tp_format, sample->cpu,
1980 sample->raw_data, sample->raw_size,
1981 trace->output);
1982 }
1983
1984 fprintf(trace->output, ")\n");
1985 return 0;
1986}
1987
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001988static void print_location(FILE *f, struct perf_sample *sample,
1989 struct addr_location *al,
1990 bool print_dso, bool print_sym)
1991{
1992
1993 if ((verbose || print_dso) && al->map)
1994 fprintf(f, "%s@", al->map->dso->long_name);
1995
1996 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001997 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001998 al->addr - al->sym->start);
1999 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002000 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002001 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002002 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002003}
2004
2005static int trace__pgfault(struct trace *trace,
2006 struct perf_evsel *evsel,
2007 union perf_event *event,
2008 struct perf_sample *sample)
2009{
2010 struct thread *thread;
2011 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
2012 struct addr_location al;
2013 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002014 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002015 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002016
2017 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002018 ttrace = thread__trace(thread, trace->output);
2019 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002020 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002021
2022 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2023 ttrace->pfmaj++;
2024 else
2025 ttrace->pfmin++;
2026
2027 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002028 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002029
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002030 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002031 sample->ip, &al);
2032
2033 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2034
2035 fprintf(trace->output, "%sfault [",
2036 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2037 "maj" : "min");
2038
2039 print_location(trace->output, sample, &al, false, true);
2040
2041 fprintf(trace->output, "] => ");
2042
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002043 thread__find_addr_location(thread, cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002044 sample->addr, &al);
2045
2046 if (!al.map) {
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002047 thread__find_addr_location(thread, cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002048 MAP__FUNCTION, sample->addr, &al);
2049
2050 if (al.map)
2051 map_type = 'x';
2052 else
2053 map_type = '?';
2054 }
2055
2056 print_location(trace->output, sample, &al, true, false);
2057
2058 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002059out:
2060 err = 0;
2061out_put:
2062 thread__put(thread);
2063 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002064}
2065
David Ahernbdc89662013-08-28 22:29:53 -06002066static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2067{
2068 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2069 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2070 return false;
2071
2072 if (trace->pid_list || trace->tid_list)
2073 return true;
2074
2075 return false;
2076}
2077
David Ahern6810fc92013-08-28 22:29:52 -06002078static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002079 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002080 struct perf_sample *sample,
2081 struct perf_evsel *evsel,
2082 struct machine *machine __maybe_unused)
2083{
2084 struct trace *trace = container_of(tool, struct trace, tool);
2085 int err = 0;
2086
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002087 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002088
David Ahernbdc89662013-08-28 22:29:53 -06002089 if (skip_sample(trace, sample))
2090 return 0;
2091
David Ahern4bb09192013-09-04 12:37:43 -06002092 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06002093 trace->base_time = sample->time;
2094
David Ahern31605652013-12-04 19:41:41 -07002095 if (handler) {
2096 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002097 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002098 }
David Ahern6810fc92013-08-28 22:29:52 -06002099
2100 return err;
2101}
2102
David Ahernbdc89662013-08-28 22:29:53 -06002103static int parse_target_str(struct trace *trace)
2104{
2105 if (trace->opts.target.pid) {
2106 trace->pid_list = intlist__new(trace->opts.target.pid);
2107 if (trace->pid_list == NULL) {
2108 pr_err("Error parsing process id string\n");
2109 return -EINVAL;
2110 }
2111 }
2112
2113 if (trace->opts.target.tid) {
2114 trace->tid_list = intlist__new(trace->opts.target.tid);
2115 if (trace->tid_list == NULL) {
2116 pr_err("Error parsing thread id string\n");
2117 return -EINVAL;
2118 }
2119 }
2120
2121 return 0;
2122}
2123
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002124static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002125{
2126 unsigned int rec_argc, i, j;
2127 const char **rec_argv;
2128 const char * const record_args[] = {
2129 "record",
2130 "-R",
2131 "-m", "1024",
2132 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002133 };
2134
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002135 const char * const sc_args[] = { "-e", };
2136 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2137 const char * const majpf_args[] = { "-e", "major-faults" };
2138 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2139 const char * const minpf_args[] = { "-e", "minor-faults" };
2140 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2141
David Ahern9aca7f12013-12-04 19:41:39 -07002142 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002143 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2144 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002145 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2146
2147 if (rec_argv == NULL)
2148 return -ENOMEM;
2149
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002150 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002151 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002152 rec_argv[j++] = record_args[i];
2153
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002154 if (trace->trace_syscalls) {
2155 for (i = 0; i < sc_args_nr; i++)
2156 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002157
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002158 /* event string may be different for older kernels - e.g., RHEL6 */
2159 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2160 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2161 else if (is_valid_tracepoint("syscalls:sys_enter"))
2162 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2163 else {
2164 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2165 return -1;
2166 }
David Ahern9aca7f12013-12-04 19:41:39 -07002167 }
David Ahern9aca7f12013-12-04 19:41:39 -07002168
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002169 if (trace->trace_pgfaults & TRACE_PFMAJ)
2170 for (i = 0; i < majpf_args_nr; i++)
2171 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002172
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002173 if (trace->trace_pgfaults & TRACE_PFMIN)
2174 for (i = 0; i < minpf_args_nr; i++)
2175 rec_argv[j++] = minpf_args[i];
2176
2177 for (i = 0; i < (unsigned int)argc; i++)
2178 rec_argv[j++] = argv[i];
2179
2180 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002181}
2182
David Ahernbf2575c2013-10-08 21:26:53 -06002183static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2184
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002185static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
2186{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002187 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002188 if (evsel == NULL)
2189 return;
2190
2191 if (perf_evsel__field(evsel, "pathname") == NULL) {
2192 perf_evsel__delete(evsel);
2193 return;
2194 }
2195
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002196 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002197 perf_evlist__add(evlist, evsel);
2198}
2199
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002200static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2201 u64 config)
2202{
2203 struct perf_evsel *evsel;
2204 struct perf_event_attr attr = {
2205 .type = PERF_TYPE_SOFTWARE,
2206 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002207 };
2208
2209 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002210 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002211
2212 event_attr_init(&attr);
2213
2214 evsel = perf_evsel__new(&attr);
2215 if (!evsel)
2216 return -ENOMEM;
2217
2218 evsel->handler = trace__pgfault;
2219 perf_evlist__add(evlist, evsel);
2220
2221 return 0;
2222}
2223
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002224static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2225{
2226 const u32 type = event->header.type;
2227 struct perf_evsel *evsel;
2228
2229 if (!trace->full_time && trace->base_time == 0)
2230 trace->base_time = sample->time;
2231
2232 if (type != PERF_RECORD_SAMPLE) {
2233 trace__process_event(trace, trace->host, event, sample);
2234 return;
2235 }
2236
2237 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2238 if (evsel == NULL) {
2239 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2240 return;
2241 }
2242
2243 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2244 sample->raw_data == NULL) {
2245 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2246 perf_evsel__name(evsel), sample->tid,
2247 sample->cpu, sample->raw_size);
2248 } else {
2249 tracepoint_handler handler = evsel->handler;
2250 handler(trace, evsel, event, sample);
2251 }
2252}
2253
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002254static int trace__add_syscall_newtp(struct trace *trace)
2255{
2256 int ret = -1;
2257 struct perf_evlist *evlist = trace->evlist;
2258 struct perf_evsel *sys_enter, *sys_exit;
2259
2260 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2261 if (sys_enter == NULL)
2262 goto out;
2263
2264 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2265 goto out_delete_sys_enter;
2266
2267 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2268 if (sys_exit == NULL)
2269 goto out_delete_sys_enter;
2270
2271 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2272 goto out_delete_sys_exit;
2273
2274 perf_evlist__add(evlist, sys_enter);
2275 perf_evlist__add(evlist, sys_exit);
2276
2277 trace->syscalls.events.enter = sys_enter;
2278 trace->syscalls.events.exit = sys_exit;
2279
2280 ret = 0;
2281out:
2282 return ret;
2283
2284out_delete_sys_exit:
2285 perf_evsel__delete_priv(sys_exit);
2286out_delete_sys_enter:
2287 perf_evsel__delete_priv(sys_enter);
2288 goto out;
2289}
2290
2291
Namhyung Kimf15eb532012-10-05 14:02:16 +09002292static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002293{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002294 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002295 int err = -1, i;
2296 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002297 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002298 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002299
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002300 trace->live = true;
2301
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002302 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002303 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002304
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002305 if (trace->trace_syscalls)
2306 perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002307
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002308 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002309 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002310 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002311 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002312
2313 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2314 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002315 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002316
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002317 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002318 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2319 trace__sched_stat_runtime))
2320 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002321
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002322 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2323 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002324 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002325 goto out_delete_evlist;
2326 }
2327
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002328 err = trace__symbols_init(trace, evlist);
2329 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002330 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002331 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002332 }
2333
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002334 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002335
Namhyung Kimf15eb532012-10-05 14:02:16 +09002336 signal(SIGCHLD, sig_handler);
2337 signal(SIGINT, sig_handler);
2338
2339 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002340 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002341 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002342 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002343 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002344 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002345 }
2346 }
2347
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002348 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002349 if (err < 0)
2350 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002351
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002352 /*
2353 * Better not use !target__has_task() here because we need to cover the
2354 * case where no threads were specified in the command line, but a
2355 * workload was, and in that case we will fill in the thread_map when
2356 * we fork the workload in perf_evlist__prepare_workload.
2357 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002358 if (trace->filter_pids.nr > 0)
2359 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002360 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002361 err = perf_evlist__set_filter_pid(evlist, getpid());
2362
2363 if (err < 0) {
2364 printf("err=%d,%s\n", -err, strerror(-err));
2365 exit(1);
2366 }
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002367
Jiri Olsaf8850372013-11-28 17:57:22 +01002368 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002369 if (err < 0)
2370 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002371
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002372 if (!target__none(&trace->opts.target))
2373 perf_evlist__enable(evlist);
2374
Namhyung Kimf15eb532012-10-05 14:02:16 +09002375 if (forks)
2376 perf_evlist__start_workload(evlist);
2377
Jiri Olsae13798c2015-06-23 00:36:02 +02002378 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002379 evlist->threads->nr > 1 ||
2380 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002381again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002382 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002383
2384 for (i = 0; i < evlist->nr_mmaps; i++) {
2385 union perf_event *event;
2386
2387 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002388 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002389
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002390 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002391
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002392 err = perf_evlist__parse_sample(evlist, event, &sample);
2393 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002394 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002395 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002396 }
2397
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002398 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002399next_event:
2400 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002401
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002402 if (interrupted)
2403 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002404
2405 if (done && !draining) {
2406 perf_evlist__disable(evlist);
2407 draining = true;
2408 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002409 }
2410 }
2411
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002412 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002413 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002414
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002415 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2416 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2417 draining = true;
2418
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002419 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002420 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002421 } else {
2422 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002423 }
2424
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002425out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002426 thread__zput(trace->current);
2427
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002428 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002429
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002430 if (!err) {
2431 if (trace->summary)
2432 trace__fprintf_thread_summary(trace, trace->output);
2433
2434 if (trace->show_tool_stats) {
2435 fprintf(trace->output, "Stats:\n "
2436 " vfs_getname : %" PRIu64 "\n"
2437 " proc_getname: %" PRIu64 "\n",
2438 trace->stats.vfs_getname,
2439 trace->stats.proc_getname);
2440 }
2441 }
David Ahernbf2575c2013-10-08 21:26:53 -06002442
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002443out_delete_evlist:
2444 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002445 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002446 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002447 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002448{
2449 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002450
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002451out_error_sched_stat_runtime:
2452 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
2453 goto out_error;
2454
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002455out_error_raw_syscalls:
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002456 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002457 goto out_error;
2458
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002459out_error_mmap:
2460 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2461 goto out_error;
2462
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002463out_error_open:
2464 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2465
2466out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002467 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302468 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002469}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002470out_error_mem:
2471 fprintf(trace->output, "Not enough memory to run!\n");
2472 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002473}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002474
David Ahern6810fc92013-08-28 22:29:52 -06002475static int trace__replay(struct trace *trace)
2476{
2477 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002478 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002479 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002480 struct perf_data_file file = {
2481 .path = input_name,
2482 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002483 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002484 };
David Ahern6810fc92013-08-28 22:29:52 -06002485 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002486 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002487 int err = -1;
2488
2489 trace->tool.sample = trace__process_sample;
2490 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002491 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002492 trace->tool.comm = perf_event__process_comm;
2493 trace->tool.exit = perf_event__process_exit;
2494 trace->tool.fork = perf_event__process_fork;
2495 trace->tool.attr = perf_event__process_attr;
2496 trace->tool.tracing_data = perf_event__process_tracing_data;
2497 trace->tool.build_id = perf_event__process_build_id;
2498
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002499 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002500 trace->tool.ordering_requires_timestamps = true;
2501
2502 /* add tid to output */
2503 trace->multiple_threads = true;
2504
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002505 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002506 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002507 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002508
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002509 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002510 goto out;
2511
David Ahern8fb598e2013-09-28 13:13:00 -06002512 trace->host = &session->machines.host;
2513
David Ahern6810fc92013-08-28 22:29:52 -06002514 err = perf_session__set_tracepoints_handlers(session, handlers);
2515 if (err)
2516 goto out;
2517
Namhyung Kim003824e2013-11-12 15:25:00 +09002518 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2519 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002520 /* older kernels have syscalls tp versus raw_syscalls */
2521 if (evsel == NULL)
2522 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2523 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002524
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002525 if (evsel &&
2526 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2527 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002528 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2529 goto out;
2530 }
2531
2532 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2533 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002534 if (evsel == NULL)
2535 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2536 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002537 if (evsel &&
2538 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2539 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002540 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002541 goto out;
2542 }
2543
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002544 evlist__for_each(session->evlist, evsel) {
2545 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2546 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2547 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2548 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2549 evsel->handler = trace__pgfault;
2550 }
2551
David Ahernbdc89662013-08-28 22:29:53 -06002552 err = parse_target_str(trace);
2553 if (err != 0)
2554 goto out;
2555
David Ahern6810fc92013-08-28 22:29:52 -06002556 setup_pager();
2557
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002558 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002559 if (err)
2560 pr_err("Failed to process events, error %d", err);
2561
David Ahernbf2575c2013-10-08 21:26:53 -06002562 else if (trace->summary)
2563 trace__fprintf_thread_summary(trace, trace->output);
2564
David Ahern6810fc92013-08-28 22:29:52 -06002565out:
2566 perf_session__delete(session);
2567
2568 return err;
2569}
2570
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002571static size_t trace__fprintf_threads_header(FILE *fp)
2572{
2573 size_t printed;
2574
Pekka Enberg99ff7152013-11-12 16:42:14 +02002575 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002576
2577 return printed;
2578}
2579
2580static size_t thread__dump_stats(struct thread_trace *ttrace,
2581 struct trace *trace, FILE *fp)
2582{
2583 struct stats *stats;
2584 size_t printed = 0;
2585 struct syscall *sc;
2586 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2587
2588 if (inode == NULL)
2589 return 0;
2590
2591 printed += fprintf(fp, "\n");
2592
Pekka Enberg27a778b2013-11-13 14:21:48 +02002593 printed += fprintf(fp, " syscall calls min avg max stddev\n");
2594 printed += fprintf(fp, " (msec) (msec) (msec) (%%)\n");
2595 printed += fprintf(fp, " --------------- -------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002596
David Ahernbf2575c2013-10-08 21:26:53 -06002597 /* each int_node is a syscall */
2598 while (inode) {
2599 stats = inode->priv;
2600 if (stats) {
2601 double min = (double)(stats->min) / NSEC_PER_MSEC;
2602 double max = (double)(stats->max) / NSEC_PER_MSEC;
2603 double avg = avg_stats(stats);
2604 double pct;
2605 u64 n = (u64) stats->n;
2606
2607 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2608 avg /= NSEC_PER_MSEC;
2609
2610 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002611 printed += fprintf(fp, " %-15s", sc->name);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002612 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f",
Pekka Enberg7f7a4132013-11-12 16:10:10 +02002613 n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002614 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002615 }
2616
2617 inode = intlist__next(inode);
2618 }
2619
2620 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002621
2622 return printed;
2623}
2624
David Ahern896cbb52013-09-28 13:12:59 -06002625/* struct used to pass data to per-thread function */
2626struct summary_data {
2627 FILE *fp;
2628 struct trace *trace;
2629 size_t printed;
2630};
2631
2632static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2633{
2634 struct summary_data *data = priv;
2635 FILE *fp = data->fp;
2636 size_t printed = data->printed;
2637 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002638 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002639 double ratio;
2640
2641 if (ttrace == NULL)
2642 return 0;
2643
2644 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2645
Pekka Enberg15e65c62013-11-14 18:43:30 +02002646 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002647 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002648 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002649 if (ttrace->pfmaj)
2650 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2651 if (ttrace->pfmin)
2652 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002653 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002654 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002655
2656 data->printed += printed;
2657
2658 return 0;
2659}
2660
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002661static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2662{
David Ahern896cbb52013-09-28 13:12:59 -06002663 struct summary_data data = {
2664 .fp = fp,
2665 .trace = trace
2666 };
2667 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002668
David Ahern896cbb52013-09-28 13:12:59 -06002669 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002670
David Ahern896cbb52013-09-28 13:12:59 -06002671 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002672}
2673
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002674static int trace__set_duration(const struct option *opt, const char *str,
2675 int unset __maybe_unused)
2676{
2677 struct trace *trace = opt->value;
2678
2679 trace->duration_filter = atof(str);
2680 return 0;
2681}
2682
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002683static int trace__set_filter_pids(const struct option *opt, const char *str,
2684 int unset __maybe_unused)
2685{
2686 int ret = -1;
2687 size_t i;
2688 struct trace *trace = opt->value;
2689 /*
2690 * FIXME: introduce a intarray class, plain parse csv and create a
2691 * { int nr, int entries[] } struct...
2692 */
2693 struct intlist *list = intlist__new(str);
2694
2695 if (list == NULL)
2696 return -1;
2697
2698 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2699 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2700
2701 if (trace->filter_pids.entries == NULL)
2702 goto out;
2703
2704 trace->filter_pids.entries[0] = getpid();
2705
2706 for (i = 1; i < trace->filter_pids.nr; ++i)
2707 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2708
2709 intlist__delete(list);
2710 ret = 0;
2711out:
2712 return ret;
2713}
2714
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002715static int trace__open_output(struct trace *trace, const char *filename)
2716{
2717 struct stat st;
2718
2719 if (!stat(filename, &st) && st.st_size) {
2720 char oldname[PATH_MAX];
2721
2722 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2723 unlink(oldname);
2724 rename(filename, oldname);
2725 }
2726
2727 trace->output = fopen(filename, "w");
2728
2729 return trace->output == NULL ? -errno : 0;
2730}
2731
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002732static int parse_pagefaults(const struct option *opt, const char *str,
2733 int unset __maybe_unused)
2734{
2735 int *trace_pgfaults = opt->value;
2736
2737 if (strcmp(str, "all") == 0)
2738 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2739 else if (strcmp(str, "maj") == 0)
2740 *trace_pgfaults |= TRACE_PFMAJ;
2741 else if (strcmp(str, "min") == 0)
2742 *trace_pgfaults |= TRACE_PFMIN;
2743 else
2744 return -1;
2745
2746 return 0;
2747}
2748
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002749static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2750{
2751 struct perf_evsel *evsel;
2752
2753 evlist__for_each(evlist, evsel)
2754 evsel->handler = handler;
2755}
2756
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002757int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2758{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002759 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002760 "perf trace [<options>] [<command>]",
2761 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002762 "perf trace record [<options>] [<command>]",
2763 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002764 NULL
2765 };
2766 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002767 .audit = {
2768 .machine = audit_detect_machine(),
2769 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2770 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002771 .syscalls = {
2772 . max = -1,
2773 },
2774 .opts = {
2775 .target = {
2776 .uid = UINT_MAX,
2777 .uses_mmap = true,
2778 },
2779 .user_freq = UINT_MAX,
2780 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002781 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002782 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002783 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002784 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002785 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002786 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002787 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002788 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002789 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002790 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002791 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002792 OPT_CALLBACK(0, "event", &trace.evlist, "event",
2793 "event selector. use 'perf list' to list available events",
2794 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002795 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2796 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002797 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03002798 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002799 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002800 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002801 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2802 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002803 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002804 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002805 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2806 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002807 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002808 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002809 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002810 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002811 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002812 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002813 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2814 "number of mmap data pages",
2815 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002816 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002817 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002818 OPT_CALLBACK(0, "duration", &trace, "float",
2819 "show only events with duration > N.M ms",
2820 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002821 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002822 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002823 OPT_BOOLEAN('T', "time", &trace.full_time,
2824 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002825 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2826 "Show only syscall summary with statistics"),
2827 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2828 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002829 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2830 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002831 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002832 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Kan Liang9d9cad72015-06-17 09:51:11 -04002833 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2834 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002835 OPT_END()
2836 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002837 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002838 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002839 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002840
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002841 signal(SIGSEGV, sighandler_dump_stack);
2842 signal(SIGFPE, sighandler_dump_stack);
2843
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002844 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002845
2846 if (trace.evlist == NULL) {
2847 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002848 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002849 goto out;
2850 }
2851
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002852 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2853 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002854
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002855 if (trace.trace_pgfaults) {
2856 trace.opts.sample_address = true;
2857 trace.opts.sample_time = true;
2858 }
2859
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002860 if (trace.evlist->nr_entries > 0)
2861 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2862
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002863 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2864 return trace__record(&trace, argc-1, &argv[1]);
2865
2866 /* summary_only implies summary option, but don't overwrite summary if set */
2867 if (trace.summary_only)
2868 trace.summary = trace.summary_only;
2869
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002870 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2871 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002872 pr_err("Please specify something to trace.\n");
2873 return -1;
2874 }
2875
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002876 if (output_name != NULL) {
2877 err = trace__open_output(&trace, output_name);
2878 if (err < 0) {
2879 perror("failed to create output file");
2880 goto out;
2881 }
2882 }
2883
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002884 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002885 const char *s = ev_qualifier_str;
2886
2887 trace.not_ev_qualifier = *s == '!';
2888 if (trace.not_ev_qualifier)
2889 ++s;
2890 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002891 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002892 fputs("Not enough memory to parse event qualifier",
2893 trace.output);
2894 err = -ENOMEM;
2895 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002896 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03002897
2898 err = trace__validate_ev_qualifier(&trace);
2899 if (err)
2900 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002901 }
2902
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002903 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002904 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002905 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002906 fprintf(trace.output, "%s", bf);
2907 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002908 }
2909
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002910 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002911 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002912 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002913 fprintf(trace.output, "%s", bf);
2914 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002915 }
2916
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002917 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002918 trace.opts.target.system_wide = true;
2919
David Ahern6810fc92013-08-28 22:29:52 -06002920 if (input_name)
2921 err = trace__replay(&trace);
2922 else
2923 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002924
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002925out_close:
2926 if (output_name != NULL)
2927 fclose(trace.output);
2928out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002929 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002930}