blob: 0ebf55bf20b356e46b92fb6478a4bac38fad2329 [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 Melo5089f202014-06-17 14:29:24 -03001190 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001191 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001192 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001193 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001194};
1195
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001196static size_t fprintf_duration(unsigned long t, FILE *fp)
1197{
1198 double duration = (double)t / NSEC_PER_MSEC;
1199 size_t printed = fprintf(fp, "(");
1200
1201 if (duration >= 1.0)
1202 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1203 else if (duration >= 0.01)
1204 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1205 else
1206 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001207 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001208}
1209
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001210struct thread_trace {
1211 u64 entry_time;
1212 u64 exit_time;
1213 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001214 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001215 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001216 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001217 double runtime_ms;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001218 struct {
1219 int max;
1220 char **table;
1221 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001222
1223 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001224};
1225
1226static struct thread_trace *thread_trace__new(void)
1227{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001228 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1229
1230 if (ttrace)
1231 ttrace->paths.max = -1;
1232
David Ahernbf2575c2013-10-08 21:26:53 -06001233 ttrace->syscall_stats = intlist__new(NULL);
1234
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001235 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001236}
1237
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001238static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001239{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001240 struct thread_trace *ttrace;
1241
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001242 if (thread == NULL)
1243 goto fail;
1244
Namhyung Kim89dceb22014-10-06 09:46:03 +09001245 if (thread__priv(thread) == NULL)
1246 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001247
Namhyung Kim89dceb22014-10-06 09:46:03 +09001248 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001249 goto fail;
1250
Namhyung Kim89dceb22014-10-06 09:46:03 +09001251 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001252 ++ttrace->nr_events;
1253
1254 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001255fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001256 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001257 "WARNING: not enough memory, dropping samples!\n");
1258 return NULL;
1259}
1260
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001261#define TRACE_PFMAJ (1 << 0)
1262#define TRACE_PFMIN (1 << 1)
1263
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001264struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001265 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001266 struct {
1267 int machine;
1268 int open_id;
1269 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001270 struct {
1271 int max;
1272 struct syscall *table;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001273 struct {
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001274 struct perf_evsel *sys_enter,
1275 *sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001276 } events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001277 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001278 struct record_opts opts;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001279 struct perf_evlist *evlist;
David Ahern8fb598e2013-09-28 13:13:00 -06001280 struct machine *host;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001281 struct thread *current;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001282 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001283 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001284 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001285 struct strlist *ev_qualifier;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001286 struct {
1287 size_t nr;
1288 int *entries;
1289 } ev_qualifier_ids;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001290 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -06001291 struct intlist *tid_list;
1292 struct intlist *pid_list;
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08001293 struct {
1294 size_t nr;
1295 pid_t *entries;
1296 } filter_pids;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001297 double duration_filter;
1298 double runtime_ms;
1299 struct {
1300 u64 vfs_getname,
1301 proc_getname;
1302 } stats;
1303 bool not_ev_qualifier;
1304 bool live;
1305 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001306 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001307 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001308 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001309 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001310 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001311 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001312 bool trace_syscalls;
Yunlong Songe366a6d2015-04-02 21:47:18 +08001313 bool force;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001314 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001315};
1316
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001317static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001318{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001319 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001320
1321 if (fd > ttrace->paths.max) {
1322 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1323
1324 if (npath == NULL)
1325 return -1;
1326
1327 if (ttrace->paths.max != -1) {
1328 memset(npath + ttrace->paths.max + 1, 0,
1329 (fd - ttrace->paths.max) * sizeof(char *));
1330 } else {
1331 memset(npath, 0, (fd + 1) * sizeof(char *));
1332 }
1333
1334 ttrace->paths.table = npath;
1335 ttrace->paths.max = fd;
1336 }
1337
1338 ttrace->paths.table[fd] = strdup(pathname);
1339
1340 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1341}
1342
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001343static int thread__read_fd_path(struct thread *thread, int fd)
1344{
1345 char linkname[PATH_MAX], pathname[PATH_MAX];
1346 struct stat st;
1347 int ret;
1348
1349 if (thread->pid_ == thread->tid) {
1350 scnprintf(linkname, sizeof(linkname),
1351 "/proc/%d/fd/%d", thread->pid_, fd);
1352 } else {
1353 scnprintf(linkname, sizeof(linkname),
1354 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1355 }
1356
1357 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1358 return -1;
1359
1360 ret = readlink(linkname, pathname, sizeof(pathname));
1361
1362 if (ret < 0 || ret > st.st_size)
1363 return -1;
1364
1365 pathname[ret] = '\0';
1366 return trace__set_fd_pathname(thread, fd, pathname);
1367}
1368
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001369static const char *thread__fd_path(struct thread *thread, int fd,
1370 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001371{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001372 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001373
1374 if (ttrace == NULL)
1375 return NULL;
1376
1377 if (fd < 0)
1378 return NULL;
1379
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001380 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001381 if (!trace->live)
1382 return NULL;
1383 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001384 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001385 return NULL;
1386 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001387
1388 return ttrace->paths.table[fd];
1389}
1390
1391static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1392 struct syscall_arg *arg)
1393{
1394 int fd = arg->val;
1395 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001396 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001397
1398 if (path)
1399 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1400
1401 return printed;
1402}
1403
1404static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1405 struct syscall_arg *arg)
1406{
1407 int fd = arg->val;
1408 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001409 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001410
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001411 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1412 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001413
1414 return printed;
1415}
1416
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001417static bool trace__filter_duration(struct trace *trace, double t)
1418{
1419 return t < (trace->duration_filter * NSEC_PER_MSEC);
1420}
1421
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001422static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1423{
1424 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1425
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001426 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001427}
1428
Namhyung Kimf15eb532012-10-05 14:02:16 +09001429static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001430static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001431
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001432static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001433{
1434 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001435 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001436}
1437
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001438static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001439 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001440{
1441 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001442 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001443
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001444 if (trace->multiple_threads) {
1445 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001446 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001447 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001448 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001449
1450 return printed;
1451}
1452
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001453static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001454 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001455{
1456 int ret = 0;
1457
1458 switch (event->header.type) {
1459 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001460 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001461 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001462 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001463 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001464 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001465 break;
1466 }
1467
1468 return ret;
1469}
1470
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001471static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001472 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001473 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001474 struct machine *machine)
1475{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001476 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001477 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001478}
1479
1480static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1481{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001482 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001483
1484 if (err)
1485 return err;
1486
David Ahern8fb598e2013-09-28 13:13:00 -06001487 trace->host = machine__new_host();
1488 if (trace->host == NULL)
1489 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001490
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001491 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001492 evlist->threads, trace__tool_process, false,
1493 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001494 if (err)
1495 symbol__exit();
1496
1497 return err;
1498}
1499
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001500static int syscall__set_arg_fmts(struct syscall *sc)
1501{
1502 struct format_field *field;
1503 int idx = 0;
1504
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001505 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001506 if (sc->arg_scnprintf == NULL)
1507 return -1;
1508
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001509 if (sc->fmt)
1510 sc->arg_parm = sc->fmt->arg_parm;
1511
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001512 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001513 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1514 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1515 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001516 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1517 ++idx;
1518 }
1519
1520 return 0;
1521}
1522
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001523static int trace__read_syscall_info(struct trace *trace, int id)
1524{
1525 char tp_name[128];
1526 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001527 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001528
1529 if (name == NULL)
1530 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001531
1532 if (id > trace->syscalls.max) {
1533 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1534
1535 if (nsyscalls == NULL)
1536 return -1;
1537
1538 if (trace->syscalls.max != -1) {
1539 memset(nsyscalls + trace->syscalls.max + 1, 0,
1540 (id - trace->syscalls.max) * sizeof(*sc));
1541 } else {
1542 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1543 }
1544
1545 trace->syscalls.table = nsyscalls;
1546 trace->syscalls.max = id;
1547 }
1548
1549 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001550 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001551
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001552 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001553
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001554 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001555 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001556
1557 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1558 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001559 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001560 }
1561
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001562 if (sc->tp_format == NULL)
1563 return -1;
1564
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001565 sc->args = sc->tp_format->format.fields;
1566 sc->nr_args = sc->tp_format->format.nr_fields;
1567 /* drop nr field - not relevant here; does not exist on older kernels */
1568 if (sc->args && strcmp(sc->args->name, "nr") == 0) {
1569 sc->args = sc->args->next;
1570 --sc->nr_args;
1571 }
1572
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001573 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1574
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001575 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001576}
1577
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001578static int trace__validate_ev_qualifier(struct trace *trace)
1579{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001580 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001581 struct str_node *pos;
1582
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001583 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1584 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1585 sizeof(trace->ev_qualifier_ids.entries[0]));
1586
1587 if (trace->ev_qualifier_ids.entries == NULL) {
1588 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1589 trace->output);
1590 err = -EINVAL;
1591 goto out;
1592 }
1593
1594 i = 0;
1595
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001596 strlist__for_each(pos, trace->ev_qualifier) {
1597 const char *sc = pos->s;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001598 int id = audit_name_to_syscall(sc, trace->audit.machine);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001599
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001600 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001601 if (err == 0) {
1602 fputs("Error:\tInvalid syscall ", trace->output);
1603 err = -EINVAL;
1604 } else {
1605 fputs(", ", trace->output);
1606 }
1607
1608 fputs(sc, trace->output);
1609 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001610
1611 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001612 }
1613
1614 if (err < 0) {
1615 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1616 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001617 zfree(&trace->ev_qualifier_ids.entries);
1618 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001619 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001620out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001621 return err;
1622}
1623
David Ahern55d43bc2015-02-19 15:00:22 -05001624/*
1625 * args is to be interpreted as a series of longs but we need to handle
1626 * 8-byte unaligned accesses. args points to raw_data within the event
1627 * and raw_data is guaranteed to be 8-byte unaligned because it is
1628 * preceded by raw_size which is a u32. So we need to copy args to a temp
1629 * variable to read it. Most notably this avoids extended load instructions
1630 * on unaligned addresses
1631 */
1632
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001633static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001634 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001635 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001636{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001637 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001638 unsigned char *p;
1639 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001640
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001641 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001642 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001643 u8 bit = 1;
1644 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001645 .idx = 0,
1646 .mask = 0,
1647 .trace = trace,
1648 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001649 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001650
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001651 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001652 field = field->next, ++arg.idx, bit <<= 1) {
1653 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001654 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001655
1656 /* special care for unaligned accesses */
1657 p = args + sizeof(unsigned long) * arg.idx;
1658 memcpy(&val, p, sizeof(val));
1659
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001660 /*
1661 * Suppress this argument if its value is zero and
1662 * and we don't have a string associated in an
1663 * strarray for it.
1664 */
David Ahern55d43bc2015-02-19 15:00:22 -05001665 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001666 !(sc->arg_scnprintf &&
1667 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1668 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001669 continue;
1670
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001671 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001672 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001673 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001674 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001675 if (sc->arg_parm)
1676 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001677 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1678 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001679 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001680 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001681 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001682 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001683 }
1684 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001685 int i = 0;
1686
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001687 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001688 /* special care for unaligned accesses */
1689 p = args + sizeof(unsigned long) * i;
1690 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001691 printed += scnprintf(bf + printed, size - printed,
1692 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001693 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001694 ++i;
1695 }
1696 }
1697
1698 return printed;
1699}
1700
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001701typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001702 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001703 struct perf_sample *sample);
1704
1705static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001706 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001707{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001708
1709 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001710
1711 /*
1712 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1713 * before that, leaving at a higher verbosity level till that is
1714 * explained. Reproduced with plain ftrace with:
1715 *
1716 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1717 * grep "NR -1 " /t/trace_pipe
1718 *
1719 * After generating some load on the machine.
1720 */
1721 if (verbose > 1) {
1722 static u64 n;
1723 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1724 id, perf_evsel__name(evsel), ++n);
1725 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001726 return NULL;
1727 }
1728
1729 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1730 trace__read_syscall_info(trace, id))
1731 goto out_cant_read;
1732
1733 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1734 goto out_cant_read;
1735
1736 return &trace->syscalls.table[id];
1737
1738out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001739 if (verbose) {
1740 fprintf(trace->output, "Problems reading syscall %d", id);
1741 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1742 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1743 fputs(" information\n", trace->output);
1744 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001745 return NULL;
1746}
1747
David Ahernbf2575c2013-10-08 21:26:53 -06001748static void thread__update_stats(struct thread_trace *ttrace,
1749 int id, struct perf_sample *sample)
1750{
1751 struct int_node *inode;
1752 struct stats *stats;
1753 u64 duration = 0;
1754
1755 inode = intlist__findnew(ttrace->syscall_stats, id);
1756 if (inode == NULL)
1757 return;
1758
1759 stats = inode->priv;
1760 if (stats == NULL) {
1761 stats = malloc(sizeof(struct stats));
1762 if (stats == NULL)
1763 return;
1764 init_stats(stats);
1765 inode->priv = stats;
1766 }
1767
1768 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1769 duration = sample->time - ttrace->entry_time;
1770
1771 update_stats(stats, duration);
1772}
1773
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001774static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1775{
1776 struct thread_trace *ttrace;
1777 u64 duration;
1778 size_t printed;
1779
1780 if (trace->current == NULL)
1781 return 0;
1782
1783 ttrace = thread__priv(trace->current);
1784
1785 if (!ttrace->entry_pending)
1786 return 0;
1787
1788 duration = sample->time - ttrace->entry_time;
1789
1790 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1791 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1792 ttrace->entry_pending = false;
1793
1794 return printed;
1795}
1796
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001797static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001798 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001799 struct perf_sample *sample)
1800{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001801 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001802 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001803 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001804 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001805 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001806 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001807 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001808
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001809 if (sc == NULL)
1810 return -1;
1811
David Ahern8fb598e2013-09-28 13:13:00 -06001812 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001813 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001814 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001815 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001816
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001817 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001818
1819 if (ttrace->entry_str == NULL) {
1820 ttrace->entry_str = malloc(1024);
1821 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001822 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001823 }
1824
David Ahern13f22a22015-03-19 12:23:03 -06001825 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001826 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001827
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001828 ttrace->entry_time = sample->time;
1829 msg = ttrace->entry_str;
1830 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1831
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001832 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1833 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001834
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001835 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001836 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001837 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1838 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001839 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001840 } else
1841 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001842
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001843 if (trace->current != thread) {
1844 thread__put(trace->current);
1845 trace->current = thread__get(thread);
1846 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001847 err = 0;
1848out_put:
1849 thread__put(thread);
1850 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001851}
1852
1853static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001854 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001855 struct perf_sample *sample)
1856{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001857 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001858 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001859 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001860 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001861 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001862 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001863
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001864 if (sc == NULL)
1865 return -1;
1866
David Ahern8fb598e2013-09-28 13:13:00 -06001867 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001868 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001869 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001870 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001871
David Ahernbf2575c2013-10-08 21:26:53 -06001872 if (trace->summary)
1873 thread__update_stats(ttrace, id, sample);
1874
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001875 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001876
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001877 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1878 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1879 trace->last_vfs_getname = NULL;
1880 ++trace->stats.vfs_getname;
1881 }
1882
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001883 ttrace->exit_time = sample->time;
1884
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001885 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001886 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001887 if (trace__filter_duration(trace, duration))
1888 goto out;
1889 } else if (trace->duration_filter)
1890 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001891
David Ahernfd2eaba2013-11-12 09:31:15 -07001892 if (trace->summary_only)
1893 goto out;
1894
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001895 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001896
1897 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001898 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001899 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001900 fprintf(trace->output, " ... [");
1901 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1902 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001903 }
1904
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001905 if (sc->fmt == NULL) {
1906signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001907 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001908 } else if (ret < 0 && sc->fmt->errmsg) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001909 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001910 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1911 *e = audit_errno_to_name(-ret);
1912
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001913 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001914 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001915 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001916 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001917 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001918 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001919 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001920
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001921 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001922out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001923 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001924 err = 0;
1925out_put:
1926 thread__put(thread);
1927 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001928}
1929
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001930static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001931 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001932 struct perf_sample *sample)
1933{
1934 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1935 return 0;
1936}
1937
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001938static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001939 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001940 struct perf_sample *sample)
1941{
1942 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1943 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001944 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001945 sample->pid,
1946 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001947 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001948
1949 if (ttrace == NULL)
1950 goto out_dump;
1951
1952 ttrace->runtime_ms += runtime_ms;
1953 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001954 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001955 return 0;
1956
1957out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001958 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001959 evsel->name,
1960 perf_evsel__strval(evsel, sample, "comm"),
1961 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1962 runtime,
1963 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001964 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001965 return 0;
1966}
1967
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001968static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1969 union perf_event *event __maybe_unused,
1970 struct perf_sample *sample)
1971{
1972 trace__printf_interrupted_entry(trace, sample);
1973 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001974
1975 if (trace->trace_syscalls)
1976 fprintf(trace->output, "( ): ");
1977
1978 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001979
1980 if (evsel->tp_format) {
1981 event_format__fprintf(evsel->tp_format, sample->cpu,
1982 sample->raw_data, sample->raw_size,
1983 trace->output);
1984 }
1985
1986 fprintf(trace->output, ")\n");
1987 return 0;
1988}
1989
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001990static void print_location(FILE *f, struct perf_sample *sample,
1991 struct addr_location *al,
1992 bool print_dso, bool print_sym)
1993{
1994
1995 if ((verbose || print_dso) && al->map)
1996 fprintf(f, "%s@", al->map->dso->long_name);
1997
1998 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001999 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002000 al->addr - al->sym->start);
2001 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002002 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002003 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002004 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002005}
2006
2007static int trace__pgfault(struct trace *trace,
2008 struct perf_evsel *evsel,
2009 union perf_event *event,
2010 struct perf_sample *sample)
2011{
2012 struct thread *thread;
2013 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
2014 struct addr_location al;
2015 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002016 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002017 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002018
2019 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002020 ttrace = thread__trace(thread, trace->output);
2021 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002022 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002023
2024 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2025 ttrace->pfmaj++;
2026 else
2027 ttrace->pfmin++;
2028
2029 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002030 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002031
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002032 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002033 sample->ip, &al);
2034
2035 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2036
2037 fprintf(trace->output, "%sfault [",
2038 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2039 "maj" : "min");
2040
2041 print_location(trace->output, sample, &al, false, true);
2042
2043 fprintf(trace->output, "] => ");
2044
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002045 thread__find_addr_location(thread, cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002046 sample->addr, &al);
2047
2048 if (!al.map) {
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002049 thread__find_addr_location(thread, cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002050 MAP__FUNCTION, sample->addr, &al);
2051
2052 if (al.map)
2053 map_type = 'x';
2054 else
2055 map_type = '?';
2056 }
2057
2058 print_location(trace->output, sample, &al, true, false);
2059
2060 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002061out:
2062 err = 0;
2063out_put:
2064 thread__put(thread);
2065 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002066}
2067
David Ahernbdc89662013-08-28 22:29:53 -06002068static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2069{
2070 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2071 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2072 return false;
2073
2074 if (trace->pid_list || trace->tid_list)
2075 return true;
2076
2077 return false;
2078}
2079
David Ahern6810fc92013-08-28 22:29:52 -06002080static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002081 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002082 struct perf_sample *sample,
2083 struct perf_evsel *evsel,
2084 struct machine *machine __maybe_unused)
2085{
2086 struct trace *trace = container_of(tool, struct trace, tool);
2087 int err = 0;
2088
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002089 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002090
David Ahernbdc89662013-08-28 22:29:53 -06002091 if (skip_sample(trace, sample))
2092 return 0;
2093
David Ahern4bb09192013-09-04 12:37:43 -06002094 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06002095 trace->base_time = sample->time;
2096
David Ahern31605652013-12-04 19:41:41 -07002097 if (handler) {
2098 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002099 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002100 }
David Ahern6810fc92013-08-28 22:29:52 -06002101
2102 return err;
2103}
2104
David Ahernbdc89662013-08-28 22:29:53 -06002105static int parse_target_str(struct trace *trace)
2106{
2107 if (trace->opts.target.pid) {
2108 trace->pid_list = intlist__new(trace->opts.target.pid);
2109 if (trace->pid_list == NULL) {
2110 pr_err("Error parsing process id string\n");
2111 return -EINVAL;
2112 }
2113 }
2114
2115 if (trace->opts.target.tid) {
2116 trace->tid_list = intlist__new(trace->opts.target.tid);
2117 if (trace->tid_list == NULL) {
2118 pr_err("Error parsing thread id string\n");
2119 return -EINVAL;
2120 }
2121 }
2122
2123 return 0;
2124}
2125
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002126static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002127{
2128 unsigned int rec_argc, i, j;
2129 const char **rec_argv;
2130 const char * const record_args[] = {
2131 "record",
2132 "-R",
2133 "-m", "1024",
2134 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002135 };
2136
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002137 const char * const sc_args[] = { "-e", };
2138 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2139 const char * const majpf_args[] = { "-e", "major-faults" };
2140 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2141 const char * const minpf_args[] = { "-e", "minor-faults" };
2142 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2143
David Ahern9aca7f12013-12-04 19:41:39 -07002144 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002145 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2146 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002147 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2148
2149 if (rec_argv == NULL)
2150 return -ENOMEM;
2151
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002152 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002153 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002154 rec_argv[j++] = record_args[i];
2155
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002156 if (trace->trace_syscalls) {
2157 for (i = 0; i < sc_args_nr; i++)
2158 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002159
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002160 /* event string may be different for older kernels - e.g., RHEL6 */
2161 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2162 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2163 else if (is_valid_tracepoint("syscalls:sys_enter"))
2164 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2165 else {
2166 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2167 return -1;
2168 }
David Ahern9aca7f12013-12-04 19:41:39 -07002169 }
David Ahern9aca7f12013-12-04 19:41:39 -07002170
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002171 if (trace->trace_pgfaults & TRACE_PFMAJ)
2172 for (i = 0; i < majpf_args_nr; i++)
2173 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002174
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002175 if (trace->trace_pgfaults & TRACE_PFMIN)
2176 for (i = 0; i < minpf_args_nr; i++)
2177 rec_argv[j++] = minpf_args[i];
2178
2179 for (i = 0; i < (unsigned int)argc; i++)
2180 rec_argv[j++] = argv[i];
2181
2182 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002183}
2184
David Ahernbf2575c2013-10-08 21:26:53 -06002185static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2186
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002187static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
2188{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002189 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002190 if (evsel == NULL)
2191 return;
2192
2193 if (perf_evsel__field(evsel, "pathname") == NULL) {
2194 perf_evsel__delete(evsel);
2195 return;
2196 }
2197
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002198 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002199 perf_evlist__add(evlist, evsel);
2200}
2201
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002202static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2203 u64 config)
2204{
2205 struct perf_evsel *evsel;
2206 struct perf_event_attr attr = {
2207 .type = PERF_TYPE_SOFTWARE,
2208 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002209 };
2210
2211 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002212 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002213
2214 event_attr_init(&attr);
2215
2216 evsel = perf_evsel__new(&attr);
2217 if (!evsel)
2218 return -ENOMEM;
2219
2220 evsel->handler = trace__pgfault;
2221 perf_evlist__add(evlist, evsel);
2222
2223 return 0;
2224}
2225
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002226static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2227{
2228 const u32 type = event->header.type;
2229 struct perf_evsel *evsel;
2230
2231 if (!trace->full_time && trace->base_time == 0)
2232 trace->base_time = sample->time;
2233
2234 if (type != PERF_RECORD_SAMPLE) {
2235 trace__process_event(trace, trace->host, event, sample);
2236 return;
2237 }
2238
2239 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2240 if (evsel == NULL) {
2241 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2242 return;
2243 }
2244
2245 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2246 sample->raw_data == NULL) {
2247 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2248 perf_evsel__name(evsel), sample->tid,
2249 sample->cpu, sample->raw_size);
2250 } else {
2251 tracepoint_handler handler = evsel->handler;
2252 handler(trace, evsel, event, sample);
2253 }
2254}
2255
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002256static int trace__add_syscall_newtp(struct trace *trace)
2257{
2258 int ret = -1;
2259 struct perf_evlist *evlist = trace->evlist;
2260 struct perf_evsel *sys_enter, *sys_exit;
2261
2262 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2263 if (sys_enter == NULL)
2264 goto out;
2265
2266 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2267 goto out_delete_sys_enter;
2268
2269 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2270 if (sys_exit == NULL)
2271 goto out_delete_sys_enter;
2272
2273 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2274 goto out_delete_sys_exit;
2275
2276 perf_evlist__add(evlist, sys_enter);
2277 perf_evlist__add(evlist, sys_exit);
2278
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002279 trace->syscalls.events.sys_enter = sys_enter;
2280 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002281
2282 ret = 0;
2283out:
2284 return ret;
2285
2286out_delete_sys_exit:
2287 perf_evsel__delete_priv(sys_exit);
2288out_delete_sys_enter:
2289 perf_evsel__delete_priv(sys_enter);
2290 goto out;
2291}
2292
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002293static int trace__set_ev_qualifier_filter(struct trace *trace)
2294{
2295 int err = -1;
2296 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2297 trace->ev_qualifier_ids.nr,
2298 trace->ev_qualifier_ids.entries);
2299
2300 if (filter == NULL)
2301 goto out_enomem;
2302
2303 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2304 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2305
2306 free(filter);
2307out:
2308 return err;
2309out_enomem:
2310 errno = ENOMEM;
2311 goto out;
2312}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002313
Namhyung Kimf15eb532012-10-05 14:02:16 +09002314static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002315{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002316 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002317 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002318 int err = -1, i;
2319 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002320 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002321 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002322
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002323 trace->live = true;
2324
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002325 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002326 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002327
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002328 if (trace->trace_syscalls)
2329 perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002330
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002331 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002332 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002333 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002334 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002335
2336 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2337 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002338 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002339
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002340 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002341 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2342 trace__sched_stat_runtime))
2343 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002344
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002345 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2346 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002347 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002348 goto out_delete_evlist;
2349 }
2350
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002351 err = trace__symbols_init(trace, evlist);
2352 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002353 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002354 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002355 }
2356
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002357 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002358
Namhyung Kimf15eb532012-10-05 14:02:16 +09002359 signal(SIGCHLD, sig_handler);
2360 signal(SIGINT, sig_handler);
2361
2362 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002363 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002364 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002365 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002366 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002367 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002368 }
2369 }
2370
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002371 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002372 if (err < 0)
2373 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002374
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002375 /*
2376 * Better not use !target__has_task() here because we need to cover the
2377 * case where no threads were specified in the command line, but a
2378 * workload was, and in that case we will fill in the thread_map when
2379 * we fork the workload in perf_evlist__prepare_workload.
2380 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002381 if (trace->filter_pids.nr > 0)
2382 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002383 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002384 err = perf_evlist__set_filter_pid(evlist, getpid());
2385
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002386 if (err < 0)
2387 goto out_error_mem;
2388
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002389 if (trace->ev_qualifier_ids.nr > 0) {
2390 err = trace__set_ev_qualifier_filter(trace);
2391 if (err < 0)
2392 goto out_errno;
2393 }
2394
2395 pr_debug("%s\n", trace->syscalls.events.sys_exit->filter);
2396
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002397 err = perf_evlist__apply_filters(evlist, &evsel);
2398 if (err < 0)
2399 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002400
Jiri Olsaf8850372013-11-28 17:57:22 +01002401 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002402 if (err < 0)
2403 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002404
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002405 if (!target__none(&trace->opts.target))
2406 perf_evlist__enable(evlist);
2407
Namhyung Kimf15eb532012-10-05 14:02:16 +09002408 if (forks)
2409 perf_evlist__start_workload(evlist);
2410
Jiri Olsae13798c2015-06-23 00:36:02 +02002411 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002412 evlist->threads->nr > 1 ||
2413 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002414again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002415 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002416
2417 for (i = 0; i < evlist->nr_mmaps; i++) {
2418 union perf_event *event;
2419
2420 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002421 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002422
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002423 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002424
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002425 err = perf_evlist__parse_sample(evlist, event, &sample);
2426 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002427 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002428 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002429 }
2430
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002431 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002432next_event:
2433 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002434
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002435 if (interrupted)
2436 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002437
2438 if (done && !draining) {
2439 perf_evlist__disable(evlist);
2440 draining = true;
2441 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002442 }
2443 }
2444
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002445 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002446 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002447
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002448 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2449 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2450 draining = true;
2451
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002452 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002453 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002454 } else {
2455 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002456 }
2457
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002458out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002459 thread__zput(trace->current);
2460
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002461 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002462
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002463 if (!err) {
2464 if (trace->summary)
2465 trace__fprintf_thread_summary(trace, trace->output);
2466
2467 if (trace->show_tool_stats) {
2468 fprintf(trace->output, "Stats:\n "
2469 " vfs_getname : %" PRIu64 "\n"
2470 " proc_getname: %" PRIu64 "\n",
2471 trace->stats.vfs_getname,
2472 trace->stats.proc_getname);
2473 }
2474 }
David Ahernbf2575c2013-10-08 21:26:53 -06002475
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002476out_delete_evlist:
2477 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002478 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002479 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002480 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002481{
2482 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002483
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002484out_error_sched_stat_runtime:
2485 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
2486 goto out_error;
2487
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002488out_error_raw_syscalls:
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002489 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002490 goto out_error;
2491
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002492out_error_mmap:
2493 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2494 goto out_error;
2495
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002496out_error_open:
2497 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2498
2499out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002500 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302501 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002502
2503out_error_apply_filters:
2504 fprintf(trace->output,
2505 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2506 evsel->filter, perf_evsel__name(evsel), errno,
2507 strerror_r(errno, errbuf, sizeof(errbuf)));
2508 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002509}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002510out_error_mem:
2511 fprintf(trace->output, "Not enough memory to run!\n");
2512 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002513
2514out_errno:
2515 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2516 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002517}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002518
David Ahern6810fc92013-08-28 22:29:52 -06002519static int trace__replay(struct trace *trace)
2520{
2521 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002522 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002523 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002524 struct perf_data_file file = {
2525 .path = input_name,
2526 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002527 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002528 };
David Ahern6810fc92013-08-28 22:29:52 -06002529 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002530 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002531 int err = -1;
2532
2533 trace->tool.sample = trace__process_sample;
2534 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002535 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002536 trace->tool.comm = perf_event__process_comm;
2537 trace->tool.exit = perf_event__process_exit;
2538 trace->tool.fork = perf_event__process_fork;
2539 trace->tool.attr = perf_event__process_attr;
2540 trace->tool.tracing_data = perf_event__process_tracing_data;
2541 trace->tool.build_id = perf_event__process_build_id;
2542
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002543 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002544 trace->tool.ordering_requires_timestamps = true;
2545
2546 /* add tid to output */
2547 trace->multiple_threads = true;
2548
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002549 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002550 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002551 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002552
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002553 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002554 goto out;
2555
David Ahern8fb598e2013-09-28 13:13:00 -06002556 trace->host = &session->machines.host;
2557
David Ahern6810fc92013-08-28 22:29:52 -06002558 err = perf_session__set_tracepoints_handlers(session, handlers);
2559 if (err)
2560 goto out;
2561
Namhyung Kim003824e2013-11-12 15:25:00 +09002562 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2563 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002564 /* older kernels have syscalls tp versus raw_syscalls */
2565 if (evsel == NULL)
2566 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2567 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002568
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002569 if (evsel &&
2570 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2571 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002572 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2573 goto out;
2574 }
2575
2576 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2577 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002578 if (evsel == NULL)
2579 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2580 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002581 if (evsel &&
2582 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2583 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002584 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002585 goto out;
2586 }
2587
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002588 evlist__for_each(session->evlist, evsel) {
2589 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2590 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2591 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2592 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2593 evsel->handler = trace__pgfault;
2594 }
2595
David Ahernbdc89662013-08-28 22:29:53 -06002596 err = parse_target_str(trace);
2597 if (err != 0)
2598 goto out;
2599
David Ahern6810fc92013-08-28 22:29:52 -06002600 setup_pager();
2601
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002602 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002603 if (err)
2604 pr_err("Failed to process events, error %d", err);
2605
David Ahernbf2575c2013-10-08 21:26:53 -06002606 else if (trace->summary)
2607 trace__fprintf_thread_summary(trace, trace->output);
2608
David Ahern6810fc92013-08-28 22:29:52 -06002609out:
2610 perf_session__delete(session);
2611
2612 return err;
2613}
2614
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002615static size_t trace__fprintf_threads_header(FILE *fp)
2616{
2617 size_t printed;
2618
Pekka Enberg99ff7152013-11-12 16:42:14 +02002619 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002620
2621 return printed;
2622}
2623
2624static size_t thread__dump_stats(struct thread_trace *ttrace,
2625 struct trace *trace, FILE *fp)
2626{
2627 struct stats *stats;
2628 size_t printed = 0;
2629 struct syscall *sc;
2630 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2631
2632 if (inode == NULL)
2633 return 0;
2634
2635 printed += fprintf(fp, "\n");
2636
Pekka Enberg27a778b2013-11-13 14:21:48 +02002637 printed += fprintf(fp, " syscall calls min avg max stddev\n");
2638 printed += fprintf(fp, " (msec) (msec) (msec) (%%)\n");
2639 printed += fprintf(fp, " --------------- -------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002640
David Ahernbf2575c2013-10-08 21:26:53 -06002641 /* each int_node is a syscall */
2642 while (inode) {
2643 stats = inode->priv;
2644 if (stats) {
2645 double min = (double)(stats->min) / NSEC_PER_MSEC;
2646 double max = (double)(stats->max) / NSEC_PER_MSEC;
2647 double avg = avg_stats(stats);
2648 double pct;
2649 u64 n = (u64) stats->n;
2650
2651 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2652 avg /= NSEC_PER_MSEC;
2653
2654 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002655 printed += fprintf(fp, " %-15s", sc->name);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002656 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f",
Pekka Enberg7f7a4132013-11-12 16:10:10 +02002657 n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002658 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002659 }
2660
2661 inode = intlist__next(inode);
2662 }
2663
2664 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002665
2666 return printed;
2667}
2668
David Ahern896cbb52013-09-28 13:12:59 -06002669/* struct used to pass data to per-thread function */
2670struct summary_data {
2671 FILE *fp;
2672 struct trace *trace;
2673 size_t printed;
2674};
2675
2676static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2677{
2678 struct summary_data *data = priv;
2679 FILE *fp = data->fp;
2680 size_t printed = data->printed;
2681 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002682 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002683 double ratio;
2684
2685 if (ttrace == NULL)
2686 return 0;
2687
2688 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2689
Pekka Enberg15e65c62013-11-14 18:43:30 +02002690 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002691 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002692 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002693 if (ttrace->pfmaj)
2694 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2695 if (ttrace->pfmin)
2696 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002697 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002698 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002699
2700 data->printed += printed;
2701
2702 return 0;
2703}
2704
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002705static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2706{
David Ahern896cbb52013-09-28 13:12:59 -06002707 struct summary_data data = {
2708 .fp = fp,
2709 .trace = trace
2710 };
2711 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002712
David Ahern896cbb52013-09-28 13:12:59 -06002713 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002714
David Ahern896cbb52013-09-28 13:12:59 -06002715 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002716}
2717
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002718static int trace__set_duration(const struct option *opt, const char *str,
2719 int unset __maybe_unused)
2720{
2721 struct trace *trace = opt->value;
2722
2723 trace->duration_filter = atof(str);
2724 return 0;
2725}
2726
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002727static int trace__set_filter_pids(const struct option *opt, const char *str,
2728 int unset __maybe_unused)
2729{
2730 int ret = -1;
2731 size_t i;
2732 struct trace *trace = opt->value;
2733 /*
2734 * FIXME: introduce a intarray class, plain parse csv and create a
2735 * { int nr, int entries[] } struct...
2736 */
2737 struct intlist *list = intlist__new(str);
2738
2739 if (list == NULL)
2740 return -1;
2741
2742 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2743 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2744
2745 if (trace->filter_pids.entries == NULL)
2746 goto out;
2747
2748 trace->filter_pids.entries[0] = getpid();
2749
2750 for (i = 1; i < trace->filter_pids.nr; ++i)
2751 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2752
2753 intlist__delete(list);
2754 ret = 0;
2755out:
2756 return ret;
2757}
2758
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002759static int trace__open_output(struct trace *trace, const char *filename)
2760{
2761 struct stat st;
2762
2763 if (!stat(filename, &st) && st.st_size) {
2764 char oldname[PATH_MAX];
2765
2766 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2767 unlink(oldname);
2768 rename(filename, oldname);
2769 }
2770
2771 trace->output = fopen(filename, "w");
2772
2773 return trace->output == NULL ? -errno : 0;
2774}
2775
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002776static int parse_pagefaults(const struct option *opt, const char *str,
2777 int unset __maybe_unused)
2778{
2779 int *trace_pgfaults = opt->value;
2780
2781 if (strcmp(str, "all") == 0)
2782 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2783 else if (strcmp(str, "maj") == 0)
2784 *trace_pgfaults |= TRACE_PFMAJ;
2785 else if (strcmp(str, "min") == 0)
2786 *trace_pgfaults |= TRACE_PFMIN;
2787 else
2788 return -1;
2789
2790 return 0;
2791}
2792
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002793static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2794{
2795 struct perf_evsel *evsel;
2796
2797 evlist__for_each(evlist, evsel)
2798 evsel->handler = handler;
2799}
2800
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002801int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2802{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002803 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002804 "perf trace [<options>] [<command>]",
2805 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002806 "perf trace record [<options>] [<command>]",
2807 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002808 NULL
2809 };
2810 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002811 .audit = {
2812 .machine = audit_detect_machine(),
2813 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2814 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002815 .syscalls = {
2816 . max = -1,
2817 },
2818 .opts = {
2819 .target = {
2820 .uid = UINT_MAX,
2821 .uses_mmap = true,
2822 },
2823 .user_freq = UINT_MAX,
2824 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002825 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002826 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002827 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002828 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002829 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002830 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002831 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002832 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002833 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002834 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002835 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002836 OPT_CALLBACK(0, "event", &trace.evlist, "event",
2837 "event selector. use 'perf list' to list available events",
2838 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002839 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2840 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002841 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03002842 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002843 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002844 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002845 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2846 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002847 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002848 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002849 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2850 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002851 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002852 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002853 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002854 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002855 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002856 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002857 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2858 "number of mmap data pages",
2859 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002860 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002861 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002862 OPT_CALLBACK(0, "duration", &trace, "float",
2863 "show only events with duration > N.M ms",
2864 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002865 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002866 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002867 OPT_BOOLEAN('T', "time", &trace.full_time,
2868 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002869 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2870 "Show only syscall summary with statistics"),
2871 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2872 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002873 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2874 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002875 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002876 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Kan Liang9d9cad72015-06-17 09:51:11 -04002877 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2878 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002879 OPT_END()
2880 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002881 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002882 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002883 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002884
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002885 signal(SIGSEGV, sighandler_dump_stack);
2886 signal(SIGFPE, sighandler_dump_stack);
2887
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002888 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002889
2890 if (trace.evlist == NULL) {
2891 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002892 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002893 goto out;
2894 }
2895
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002896 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2897 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002898
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002899 if (trace.trace_pgfaults) {
2900 trace.opts.sample_address = true;
2901 trace.opts.sample_time = true;
2902 }
2903
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002904 if (trace.evlist->nr_entries > 0)
2905 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2906
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002907 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2908 return trace__record(&trace, argc-1, &argv[1]);
2909
2910 /* summary_only implies summary option, but don't overwrite summary if set */
2911 if (trace.summary_only)
2912 trace.summary = trace.summary_only;
2913
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002914 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2915 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002916 pr_err("Please specify something to trace.\n");
2917 return -1;
2918 }
2919
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002920 if (output_name != NULL) {
2921 err = trace__open_output(&trace, output_name);
2922 if (err < 0) {
2923 perror("failed to create output file");
2924 goto out;
2925 }
2926 }
2927
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002928 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002929 const char *s = ev_qualifier_str;
2930
2931 trace.not_ev_qualifier = *s == '!';
2932 if (trace.not_ev_qualifier)
2933 ++s;
2934 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002935 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002936 fputs("Not enough memory to parse event qualifier",
2937 trace.output);
2938 err = -ENOMEM;
2939 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002940 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03002941
2942 err = trace__validate_ev_qualifier(&trace);
2943 if (err)
2944 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002945 }
2946
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002947 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002948 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002949 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002950 fprintf(trace.output, "%s", bf);
2951 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002952 }
2953
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002954 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002955 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002956 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002957 fprintf(trace.output, "%s", bf);
2958 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002959 }
2960
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002961 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002962 trace.opts.target.system_wide = true;
2963
David Ahern6810fc92013-08-28 22:29:52 -06002964 if (input_name)
2965 err = trace__replay(&trace);
2966 else
2967 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002968
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002969out_close:
2970 if (output_name != NULL)
2971 fclose(trace.output);
2972out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002973 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002974}