blob: aa1e2888c81d024f5a63f19e5d656fa707afd9d7 [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 Melo005438a2015-07-20 12:02:09 -03006#include "util/exec_cmd.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03007#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -06008#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03009#include "util/thread.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030010#include "util/parse-options.h"
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030011#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060012#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030013#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060014#include "util/stat.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010015#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070016#include "util/parse-events.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030017
18#include <libaudit.h>
19#include <stdlib.h>
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030020#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030021#include <linux/futex.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030022
Ingo Molnar456857b2013-09-12 15:29:00 +020023/* For older distros: */
24#ifndef MAP_STACK
25# define MAP_STACK 0x20000
26#endif
27
28#ifndef MADV_HWPOISON
29# define MADV_HWPOISON 100
30#endif
31
32#ifndef MADV_MERGEABLE
33# define MADV_MERGEABLE 12
34#endif
35
36#ifndef MADV_UNMERGEABLE
37# define MADV_UNMERGEABLE 13
38#endif
39
Ben Hutchings79d26a62014-02-06 01:00:35 +000040#ifndef EFD_SEMAPHORE
41# define EFD_SEMAPHORE 1
42#endif
43
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030044#ifndef EFD_NONBLOCK
45# define EFD_NONBLOCK 00004000
46#endif
47
48#ifndef EFD_CLOEXEC
49# define EFD_CLOEXEC 02000000
50#endif
51
52#ifndef O_CLOEXEC
53# define O_CLOEXEC 02000000
54#endif
55
56#ifndef SOCK_DCCP
57# define SOCK_DCCP 6
58#endif
59
60#ifndef SOCK_CLOEXEC
61# define SOCK_CLOEXEC 02000000
62#endif
63
64#ifndef SOCK_NONBLOCK
65# define SOCK_NONBLOCK 00004000
66#endif
67
68#ifndef MSG_CMSG_CLOEXEC
69# define MSG_CMSG_CLOEXEC 0x40000000
70#endif
71
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -030072#ifndef PERF_FLAG_FD_NO_GROUP
73# define PERF_FLAG_FD_NO_GROUP (1UL << 0)
74#endif
75
76#ifndef PERF_FLAG_FD_OUTPUT
77# define PERF_FLAG_FD_OUTPUT (1UL << 1)
78#endif
79
80#ifndef PERF_FLAG_PID_CGROUP
81# define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */
82#endif
83
84#ifndef PERF_FLAG_FD_CLOEXEC
85# define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */
86#endif
87
88
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -030089struct tp_field {
90 int offset;
91 union {
92 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
93 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
94 };
95};
96
97#define TP_UINT_FIELD(bits) \
98static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
99{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500100 u##bits value; \
101 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
102 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300103}
104
105TP_UINT_FIELD(8);
106TP_UINT_FIELD(16);
107TP_UINT_FIELD(32);
108TP_UINT_FIELD(64);
109
110#define TP_UINT_FIELD__SWAPPED(bits) \
111static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
112{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500113 u##bits value; \
114 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300115 return bswap_##bits(value);\
116}
117
118TP_UINT_FIELD__SWAPPED(16);
119TP_UINT_FIELD__SWAPPED(32);
120TP_UINT_FIELD__SWAPPED(64);
121
122static int tp_field__init_uint(struct tp_field *field,
123 struct format_field *format_field,
124 bool needs_swap)
125{
126 field->offset = format_field->offset;
127
128 switch (format_field->size) {
129 case 1:
130 field->integer = tp_field__u8;
131 break;
132 case 2:
133 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
134 break;
135 case 4:
136 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
137 break;
138 case 8:
139 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
140 break;
141 default:
142 return -1;
143 }
144
145 return 0;
146}
147
148static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
149{
150 return sample->raw_data + field->offset;
151}
152
153static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
154{
155 field->offset = format_field->offset;
156 field->pointer = tp_field__ptr;
157 return 0;
158}
159
160struct syscall_tp {
161 struct tp_field id;
162 union {
163 struct tp_field args, ret;
164 };
165};
166
167static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
168 struct tp_field *field,
169 const char *name)
170{
171 struct format_field *format_field = perf_evsel__field(evsel, name);
172
173 if (format_field == NULL)
174 return -1;
175
176 return tp_field__init_uint(field, format_field, evsel->needs_swap);
177}
178
179#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
180 ({ struct syscall_tp *sc = evsel->priv;\
181 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
182
183static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
184 struct tp_field *field,
185 const char *name)
186{
187 struct format_field *format_field = perf_evsel__field(evsel, name);
188
189 if (format_field == NULL)
190 return -1;
191
192 return tp_field__init_ptr(field, format_field);
193}
194
195#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
196 ({ struct syscall_tp *sc = evsel->priv;\
197 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
198
199static void perf_evsel__delete_priv(struct perf_evsel *evsel)
200{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300201 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300202 perf_evsel__delete(evsel);
203}
204
Namhyung Kim96695d42013-11-12 08:51:45 -0300205static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
206{
207 evsel->priv = malloc(sizeof(struct syscall_tp));
208 if (evsel->priv != NULL) {
209 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
210 goto out_delete;
211
212 evsel->handler = handler;
213 return 0;
214 }
215
216 return -ENOMEM;
217
218out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300219 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300220 return -ENOENT;
221}
222
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300223static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300224{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300225 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300226
David Ahern9aca7f12013-12-04 19:41:39 -0700227 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
228 if (evsel == NULL)
229 evsel = perf_evsel__newtp("syscalls", direction);
230
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300231 if (evsel) {
Namhyung Kim96695d42013-11-12 08:51:45 -0300232 if (perf_evsel__init_syscall_tp(evsel, handler))
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300233 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300234 }
235
236 return evsel;
237
238out_delete:
239 perf_evsel__delete_priv(evsel);
240 return NULL;
241}
242
243#define perf_evsel__sc_tp_uint(evsel, name, sample) \
244 ({ struct syscall_tp *fields = evsel->priv; \
245 fields->name.integer(&fields->name, sample); })
246
247#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
248 ({ struct syscall_tp *fields = evsel->priv; \
249 fields->name.pointer(&fields->name, sample); })
250
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300251struct syscall_arg {
252 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300253 struct thread *thread;
254 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300255 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300256 u8 idx;
257 u8 mask;
258};
259
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300260struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300261 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300262 int nr_entries;
263 const char **entries;
264};
265
266#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
267 .nr_entries = ARRAY_SIZE(array), \
268 .entries = array, \
269}
270
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300271#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
272 .offset = off, \
273 .nr_entries = ARRAY_SIZE(array), \
274 .entries = array, \
275}
276
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300277static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
278 const char *intfmt,
279 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300280{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300281 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300282 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300283
284 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300285 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300286
287 return scnprintf(bf, size, "%s", sa->entries[idx]);
288}
289
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300290static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
291 struct syscall_arg *arg)
292{
293 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
294}
295
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300296#define SCA_STRARRAY syscall_arg__scnprintf_strarray
297
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300298#if defined(__i386__) || defined(__x86_64__)
299/*
300 * FIXME: Make this available to all arches as soon as the ioctl beautifier
301 * gets rewritten to support all arches.
302 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300303static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
304 struct syscall_arg *arg)
305{
306 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
307}
308
309#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300310#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300311
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300312static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
313 struct syscall_arg *arg);
314
315#define SCA_FD syscall_arg__scnprintf_fd
316
317static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
318 struct syscall_arg *arg)
319{
320 int fd = arg->val;
321
322 if (fd == AT_FDCWD)
323 return scnprintf(bf, size, "CWD");
324
325 return syscall_arg__scnprintf_fd(bf, size, arg);
326}
327
328#define SCA_FDAT syscall_arg__scnprintf_fd_at
329
330static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
331 struct syscall_arg *arg);
332
333#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
334
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300335static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300336 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300337{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300338 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300339}
340
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300341#define SCA_HEX syscall_arg__scnprintf_hex
342
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300343static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
344 struct syscall_arg *arg)
345{
346 return scnprintf(bf, size, "%d", arg->val);
347}
348
349#define SCA_INT syscall_arg__scnprintf_int
350
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300351static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300352 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300353{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300354 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300355
356 if (prot == PROT_NONE)
357 return scnprintf(bf, size, "NONE");
358#define P_MMAP_PROT(n) \
359 if (prot & PROT_##n) { \
360 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
361 prot &= ~PROT_##n; \
362 }
363
364 P_MMAP_PROT(EXEC);
365 P_MMAP_PROT(READ);
366 P_MMAP_PROT(WRITE);
367#ifdef PROT_SEM
368 P_MMAP_PROT(SEM);
369#endif
370 P_MMAP_PROT(GROWSDOWN);
371 P_MMAP_PROT(GROWSUP);
372#undef P_MMAP_PROT
373
374 if (prot)
375 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
376
377 return printed;
378}
379
380#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
381
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300382static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300383 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300384{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300385 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300386
387#define P_MMAP_FLAG(n) \
388 if (flags & MAP_##n) { \
389 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
390 flags &= ~MAP_##n; \
391 }
392
393 P_MMAP_FLAG(SHARED);
394 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400395#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300396 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400397#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300398 P_MMAP_FLAG(ANONYMOUS);
399 P_MMAP_FLAG(DENYWRITE);
400 P_MMAP_FLAG(EXECUTABLE);
401 P_MMAP_FLAG(FILE);
402 P_MMAP_FLAG(FIXED);
403 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600404#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300405 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600406#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300407 P_MMAP_FLAG(LOCKED);
408 P_MMAP_FLAG(NONBLOCK);
409 P_MMAP_FLAG(NORESERVE);
410 P_MMAP_FLAG(POPULATE);
411 P_MMAP_FLAG(STACK);
412#ifdef MAP_UNINITIALIZED
413 P_MMAP_FLAG(UNINITIALIZED);
414#endif
415#undef P_MMAP_FLAG
416
417 if (flags)
418 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
419
420 return printed;
421}
422
423#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
424
Alex Snast86998dd2014-08-13 18:42:40 +0300425static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
426 struct syscall_arg *arg)
427{
428 int printed = 0, flags = arg->val;
429
430#define P_MREMAP_FLAG(n) \
431 if (flags & MREMAP_##n) { \
432 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
433 flags &= ~MREMAP_##n; \
434 }
435
436 P_MREMAP_FLAG(MAYMOVE);
437#ifdef MREMAP_FIXED
438 P_MREMAP_FLAG(FIXED);
439#endif
440#undef P_MREMAP_FLAG
441
442 if (flags)
443 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
444
445 return printed;
446}
447
448#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
449
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300450static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300451 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300452{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300453 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300454
455 switch (behavior) {
456#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
457 P_MADV_BHV(NORMAL);
458 P_MADV_BHV(RANDOM);
459 P_MADV_BHV(SEQUENTIAL);
460 P_MADV_BHV(WILLNEED);
461 P_MADV_BHV(DONTNEED);
462 P_MADV_BHV(REMOVE);
463 P_MADV_BHV(DONTFORK);
464 P_MADV_BHV(DOFORK);
465 P_MADV_BHV(HWPOISON);
466#ifdef MADV_SOFT_OFFLINE
467 P_MADV_BHV(SOFT_OFFLINE);
468#endif
469 P_MADV_BHV(MERGEABLE);
470 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600471#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300472 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600473#endif
474#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300475 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600476#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300477#ifdef MADV_DONTDUMP
478 P_MADV_BHV(DONTDUMP);
479#endif
480#ifdef MADV_DODUMP
481 P_MADV_BHV(DODUMP);
482#endif
483#undef P_MADV_PHV
484 default: break;
485 }
486
487 return scnprintf(bf, size, "%#x", behavior);
488}
489
490#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
491
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300492static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
493 struct syscall_arg *arg)
494{
495 int printed = 0, op = arg->val;
496
497 if (op == 0)
498 return scnprintf(bf, size, "NONE");
499#define P_CMD(cmd) \
500 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
501 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
502 op &= ~LOCK_##cmd; \
503 }
504
505 P_CMD(SH);
506 P_CMD(EX);
507 P_CMD(NB);
508 P_CMD(UN);
509 P_CMD(MAND);
510 P_CMD(RW);
511 P_CMD(READ);
512 P_CMD(WRITE);
513#undef P_OP
514
515 if (op)
516 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
517
518 return printed;
519}
520
521#define SCA_FLOCK syscall_arg__scnprintf_flock
522
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300523static 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 -0300524{
525 enum syscall_futex_args {
526 SCF_UADDR = (1 << 0),
527 SCF_OP = (1 << 1),
528 SCF_VAL = (1 << 2),
529 SCF_TIMEOUT = (1 << 3),
530 SCF_UADDR2 = (1 << 4),
531 SCF_VAL3 = (1 << 5),
532 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300533 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300534 int cmd = op & FUTEX_CMD_MASK;
535 size_t printed = 0;
536
537 switch (cmd) {
538#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300539 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
540 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
541 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
542 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
543 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
544 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300545 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300546 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
547 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
548 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
549 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
550 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300551 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
552 default: printed = scnprintf(bf, size, "%#x", cmd); break;
553 }
554
555 if (op & FUTEX_PRIVATE_FLAG)
556 printed += scnprintf(bf + printed, size - printed, "|PRIV");
557
558 if (op & FUTEX_CLOCK_REALTIME)
559 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
560
561 return printed;
562}
563
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300564#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
565
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300566static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
567static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300568
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300569static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
570static DEFINE_STRARRAY(itimers);
571
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300572static const char *whences[] = { "SET", "CUR", "END",
573#ifdef SEEK_DATA
574"DATA",
575#endif
576#ifdef SEEK_HOLE
577"HOLE",
578#endif
579};
580static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300581
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300582static const char *fcntl_cmds[] = {
583 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
584 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
585 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
586 "F_GETOWNER_UIDS",
587};
588static DEFINE_STRARRAY(fcntl_cmds);
589
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300590static const char *rlimit_resources[] = {
591 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
592 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
593 "RTTIME",
594};
595static DEFINE_STRARRAY(rlimit_resources);
596
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300597static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
598static DEFINE_STRARRAY(sighow);
599
David Ahern4f8c1b72013-09-22 19:45:00 -0600600static const char *clockid[] = {
601 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
602 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
603};
604static DEFINE_STRARRAY(clockid);
605
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300606static const char *socket_families[] = {
607 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
608 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
609 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
610 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
611 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
612 "ALG", "NFC", "VSOCK",
613};
614static DEFINE_STRARRAY(socket_families);
615
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300616#ifndef SOCK_TYPE_MASK
617#define SOCK_TYPE_MASK 0xf
618#endif
619
620static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
621 struct syscall_arg *arg)
622{
623 size_t printed;
624 int type = arg->val,
625 flags = type & ~SOCK_TYPE_MASK;
626
627 type &= SOCK_TYPE_MASK;
628 /*
629 * Can't use a strarray, MIPS may override for ABI reasons.
630 */
631 switch (type) {
632#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
633 P_SK_TYPE(STREAM);
634 P_SK_TYPE(DGRAM);
635 P_SK_TYPE(RAW);
636 P_SK_TYPE(RDM);
637 P_SK_TYPE(SEQPACKET);
638 P_SK_TYPE(DCCP);
639 P_SK_TYPE(PACKET);
640#undef P_SK_TYPE
641 default:
642 printed = scnprintf(bf, size, "%#x", type);
643 }
644
645#define P_SK_FLAG(n) \
646 if (flags & SOCK_##n) { \
647 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
648 flags &= ~SOCK_##n; \
649 }
650
651 P_SK_FLAG(CLOEXEC);
652 P_SK_FLAG(NONBLOCK);
653#undef P_SK_FLAG
654
655 if (flags)
656 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
657
658 return printed;
659}
660
661#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
662
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300663#ifndef MSG_PROBE
664#define MSG_PROBE 0x10
665#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600666#ifndef MSG_WAITFORONE
667#define MSG_WAITFORONE 0x10000
668#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300669#ifndef MSG_SENDPAGE_NOTLAST
670#define MSG_SENDPAGE_NOTLAST 0x20000
671#endif
672#ifndef MSG_FASTOPEN
673#define MSG_FASTOPEN 0x20000000
674#endif
675
676static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
677 struct syscall_arg *arg)
678{
679 int printed = 0, flags = arg->val;
680
681 if (flags == 0)
682 return scnprintf(bf, size, "NONE");
683#define P_MSG_FLAG(n) \
684 if (flags & MSG_##n) { \
685 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
686 flags &= ~MSG_##n; \
687 }
688
689 P_MSG_FLAG(OOB);
690 P_MSG_FLAG(PEEK);
691 P_MSG_FLAG(DONTROUTE);
692 P_MSG_FLAG(TRYHARD);
693 P_MSG_FLAG(CTRUNC);
694 P_MSG_FLAG(PROBE);
695 P_MSG_FLAG(TRUNC);
696 P_MSG_FLAG(DONTWAIT);
697 P_MSG_FLAG(EOR);
698 P_MSG_FLAG(WAITALL);
699 P_MSG_FLAG(FIN);
700 P_MSG_FLAG(SYN);
701 P_MSG_FLAG(CONFIRM);
702 P_MSG_FLAG(RST);
703 P_MSG_FLAG(ERRQUEUE);
704 P_MSG_FLAG(NOSIGNAL);
705 P_MSG_FLAG(MORE);
706 P_MSG_FLAG(WAITFORONE);
707 P_MSG_FLAG(SENDPAGE_NOTLAST);
708 P_MSG_FLAG(FASTOPEN);
709 P_MSG_FLAG(CMSG_CLOEXEC);
710#undef P_MSG_FLAG
711
712 if (flags)
713 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
714
715 return printed;
716}
717
718#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
719
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300720static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
721 struct syscall_arg *arg)
722{
723 size_t printed = 0;
724 int mode = arg->val;
725
726 if (mode == F_OK) /* 0 */
727 return scnprintf(bf, size, "F");
728#define P_MODE(n) \
729 if (mode & n##_OK) { \
730 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
731 mode &= ~n##_OK; \
732 }
733
734 P_MODE(R);
735 P_MODE(W);
736 P_MODE(X);
737#undef P_MODE
738
739 if (mode)
740 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
741
742 return printed;
743}
744
745#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
746
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300747static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300748 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300749{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300750 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300751
752 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300753 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300754
755 if (flags == 0)
756 return scnprintf(bf, size, "RDONLY");
757#define P_FLAG(n) \
758 if (flags & O_##n) { \
759 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
760 flags &= ~O_##n; \
761 }
762
763 P_FLAG(APPEND);
764 P_FLAG(ASYNC);
765 P_FLAG(CLOEXEC);
766 P_FLAG(CREAT);
767 P_FLAG(DIRECT);
768 P_FLAG(DIRECTORY);
769 P_FLAG(EXCL);
770 P_FLAG(LARGEFILE);
771 P_FLAG(NOATIME);
772 P_FLAG(NOCTTY);
773#ifdef O_NONBLOCK
774 P_FLAG(NONBLOCK);
775#elif O_NDELAY
776 P_FLAG(NDELAY);
777#endif
778#ifdef O_PATH
779 P_FLAG(PATH);
780#endif
781 P_FLAG(RDWR);
782#ifdef O_DSYNC
783 if ((flags & O_SYNC) == O_SYNC)
784 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
785 else {
786 P_FLAG(DSYNC);
787 }
788#else
789 P_FLAG(SYNC);
790#endif
791 P_FLAG(TRUNC);
792 P_FLAG(WRONLY);
793#undef P_FLAG
794
795 if (flags)
796 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
797
798 return printed;
799}
800
801#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
802
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300803static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size,
804 struct syscall_arg *arg)
805{
806 int printed = 0, flags = arg->val;
807
808 if (flags == 0)
809 return 0;
810
811#define P_FLAG(n) \
812 if (flags & PERF_FLAG_##n) { \
813 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
814 flags &= ~PERF_FLAG_##n; \
815 }
816
817 P_FLAG(FD_NO_GROUP);
818 P_FLAG(FD_OUTPUT);
819 P_FLAG(PID_CGROUP);
820 P_FLAG(FD_CLOEXEC);
821#undef P_FLAG
822
823 if (flags)
824 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
825
826 return printed;
827}
828
829#define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags
830
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300831static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
832 struct syscall_arg *arg)
833{
834 int printed = 0, flags = arg->val;
835
836 if (flags == 0)
837 return scnprintf(bf, size, "NONE");
838#define P_FLAG(n) \
839 if (flags & EFD_##n) { \
840 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
841 flags &= ~EFD_##n; \
842 }
843
844 P_FLAG(SEMAPHORE);
845 P_FLAG(CLOEXEC);
846 P_FLAG(NONBLOCK);
847#undef P_FLAG
848
849 if (flags)
850 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
851
852 return printed;
853}
854
855#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
856
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300857static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
858 struct syscall_arg *arg)
859{
860 int printed = 0, flags = arg->val;
861
862#define P_FLAG(n) \
863 if (flags & O_##n) { \
864 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
865 flags &= ~O_##n; \
866 }
867
868 P_FLAG(CLOEXEC);
869 P_FLAG(NONBLOCK);
870#undef P_FLAG
871
872 if (flags)
873 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
874
875 return printed;
876}
877
878#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
879
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300880static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
881{
882 int sig = arg->val;
883
884 switch (sig) {
885#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
886 P_SIGNUM(HUP);
887 P_SIGNUM(INT);
888 P_SIGNUM(QUIT);
889 P_SIGNUM(ILL);
890 P_SIGNUM(TRAP);
891 P_SIGNUM(ABRT);
892 P_SIGNUM(BUS);
893 P_SIGNUM(FPE);
894 P_SIGNUM(KILL);
895 P_SIGNUM(USR1);
896 P_SIGNUM(SEGV);
897 P_SIGNUM(USR2);
898 P_SIGNUM(PIPE);
899 P_SIGNUM(ALRM);
900 P_SIGNUM(TERM);
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300901 P_SIGNUM(CHLD);
902 P_SIGNUM(CONT);
903 P_SIGNUM(STOP);
904 P_SIGNUM(TSTP);
905 P_SIGNUM(TTIN);
906 P_SIGNUM(TTOU);
907 P_SIGNUM(URG);
908 P_SIGNUM(XCPU);
909 P_SIGNUM(XFSZ);
910 P_SIGNUM(VTALRM);
911 P_SIGNUM(PROF);
912 P_SIGNUM(WINCH);
913 P_SIGNUM(IO);
914 P_SIGNUM(PWR);
915 P_SIGNUM(SYS);
Ben Hutchings02c5bb42014-02-06 01:00:41 +0000916#ifdef SIGEMT
917 P_SIGNUM(EMT);
918#endif
919#ifdef SIGSTKFLT
920 P_SIGNUM(STKFLT);
921#endif
922#ifdef SIGSWI
923 P_SIGNUM(SWI);
924#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300925 default: break;
926 }
927
928 return scnprintf(bf, size, "%#x", sig);
929}
930
931#define SCA_SIGNUM syscall_arg__scnprintf_signum
932
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300933#if defined(__i386__) || defined(__x86_64__)
934/*
935 * FIXME: Make this available to all arches.
936 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300937#define TCGETS 0x5401
938
939static const char *tioctls[] = {
940 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
941 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
942 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
943 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
944 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
945 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
946 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
947 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
948 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
949 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
950 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
951 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
952 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
953 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
954 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
955};
956
957static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300958#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300959
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300960#define STRARRAY(arg, name, array) \
961 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
962 .arg_parm = { [arg] = &strarray__##array, }
963
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300964static struct syscall_fmt {
965 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300966 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300967 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300968 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300969 bool errmsg;
970 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300971 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300972} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300973 { .name = "access", .errmsg = true,
974 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300975 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300976 { .name = "brk", .hexret = true,
977 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600978 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300979 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300980 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300981 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300982 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300983 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300984 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300985 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300986 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300987 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300988 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300989 { .name = "eventfd2", .errmsg = true,
990 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300991 { .name = "faccessat", .errmsg = true,
992 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
993 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300994 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300995 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300996 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300997 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300998 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300999 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001000 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001001 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001002 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001003 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001004 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001005 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001006 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001007 { .name = "fcntl", .errmsg = true,
1008 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1009 [1] = SCA_STRARRAY, /* cmd */ },
1010 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1011 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001012 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -03001013 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001014 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1015 [1] = SCA_FLOCK, /* cmd */ }, },
1016 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001017 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001018 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001019 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001020 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001021 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001022 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001023 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001024 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001025 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001026 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001027 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -03001028 { .name = "futex", .errmsg = true,
1029 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001030 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001031 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001032 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001033 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001034 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001035 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001036 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1037 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001038 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001039 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001040#if defined(__i386__) || defined(__x86_64__)
1041/*
1042 * FIXME: Make this available to all arches.
1043 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001044 [1] = SCA_STRHEXARRAY, /* cmd */
1045 [2] = SCA_HEX, /* arg */ },
1046 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001047#else
1048 [2] = SCA_HEX, /* arg */ }, },
1049#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001050 { .name = "kill", .errmsg = true,
1051 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001052 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001053 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001054 { .name = "lseek", .errmsg = true,
1055 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1056 [2] = SCA_STRARRAY, /* whence */ },
1057 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001058 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001059 { .name = "madvise", .errmsg = true,
1060 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1061 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001062 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001063 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001064 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001065 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001066 { .name = "mlock", .errmsg = true,
1067 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1068 { .name = "mlockall", .errmsg = true,
1069 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001070 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001071 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001072 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001073 [3] = SCA_MMAP_FLAGS, /* flags */
1074 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001075 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001076 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1077 [2] = SCA_MMAP_PROT, /* prot */ }, },
1078 { .name = "mremap", .hexret = true,
1079 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001080 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001081 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001082 { .name = "munlock", .errmsg = true,
1083 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001084 { .name = "munmap", .errmsg = true,
1085 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001086 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001087 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001088 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001089 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001090 { .name = "open", .errmsg = true,
1091 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001092 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001093 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1094 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001095 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001096 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1097 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001098 { .name = "perf_event_open", .errmsg = true,
1099 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1100 [2] = SCA_INT, /* cpu */
1101 [3] = SCA_FD, /* group_fd */
1102 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001103 { .name = "pipe2", .errmsg = true,
1104 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001105 { .name = "poll", .errmsg = true, .timeout = true, },
1106 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001107 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001108 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001109 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001110 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001111 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001112 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001113 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001114 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001115 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001116 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001117 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001118 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001119 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001120 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001121 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001122 { .name = "recvfrom", .errmsg = true,
1123 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1124 { .name = "recvmmsg", .errmsg = true,
1125 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1126 { .name = "recvmsg", .errmsg = true,
1127 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001128 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001129 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001130 { .name = "rt_sigaction", .errmsg = true,
1131 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001132 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001133 { .name = "rt_sigqueueinfo", .errmsg = true,
1134 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1135 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1136 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001137 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001138 { .name = "sendmmsg", .errmsg = true,
1139 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1140 { .name = "sendmsg", .errmsg = true,
1141 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
1142 { .name = "sendto", .errmsg = true,
1143 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001144 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1145 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001146 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001147 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001148 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001149 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1150 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001151 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001152 { .name = "socketpair", .errmsg = true,
1153 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1154 [1] = SCA_SK_TYPE, /* type */ },
1155 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001156 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001157 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001158 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001159 { .name = "tgkill", .errmsg = true,
1160 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1161 { .name = "tkill", .errmsg = true,
1162 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001163 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001164 { .name = "unlinkat", .errmsg = true,
1165 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1166 { .name = "utimensat", .errmsg = true,
1167 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
1168 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001169 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001170 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001171 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001172};
1173
1174static int syscall_fmt__cmp(const void *name, const void *fmtp)
1175{
1176 const struct syscall_fmt *fmt = fmtp;
1177 return strcmp(name, fmt->name);
1178}
1179
1180static struct syscall_fmt *syscall_fmt__find(const char *name)
1181{
1182 const int nmemb = ARRAY_SIZE(syscall_fmts);
1183 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1184}
1185
1186struct syscall {
1187 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001188 int nr_args;
1189 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001190 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001191 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001192 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001193 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001194 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001195};
1196
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001197static size_t fprintf_duration(unsigned long t, FILE *fp)
1198{
1199 double duration = (double)t / NSEC_PER_MSEC;
1200 size_t printed = fprintf(fp, "(");
1201
1202 if (duration >= 1.0)
1203 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1204 else if (duration >= 0.01)
1205 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1206 else
1207 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001208 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001209}
1210
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001211struct thread_trace {
1212 u64 entry_time;
1213 u64 exit_time;
1214 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001215 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001216 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001217 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001218 double runtime_ms;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001219 struct {
1220 int max;
1221 char **table;
1222 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001223
1224 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001225};
1226
1227static struct thread_trace *thread_trace__new(void)
1228{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001229 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1230
1231 if (ttrace)
1232 ttrace->paths.max = -1;
1233
David Ahernbf2575c2013-10-08 21:26:53 -06001234 ttrace->syscall_stats = intlist__new(NULL);
1235
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001236 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001237}
1238
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001239static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001240{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001241 struct thread_trace *ttrace;
1242
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001243 if (thread == NULL)
1244 goto fail;
1245
Namhyung Kim89dceb22014-10-06 09:46:03 +09001246 if (thread__priv(thread) == NULL)
1247 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001248
Namhyung Kim89dceb22014-10-06 09:46:03 +09001249 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001250 goto fail;
1251
Namhyung Kim89dceb22014-10-06 09:46:03 +09001252 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001253 ++ttrace->nr_events;
1254
1255 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001256fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001257 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001258 "WARNING: not enough memory, dropping samples!\n");
1259 return NULL;
1260}
1261
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001262#define TRACE_PFMAJ (1 << 0)
1263#define TRACE_PFMIN (1 << 1)
1264
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001265struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001266 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001267 struct {
1268 int machine;
1269 int open_id;
1270 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001271 struct {
1272 int max;
1273 struct syscall *table;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001274 struct {
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001275 struct perf_evsel *sys_enter,
1276 *sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001277 } events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001278 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001279 struct record_opts opts;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001280 struct perf_evlist *evlist;
David Ahern8fb598e2013-09-28 13:13:00 -06001281 struct machine *host;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001282 struct thread *current;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001283 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001284 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001285 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001286 struct strlist *ev_qualifier;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001287 struct {
1288 size_t nr;
1289 int *entries;
1290 } ev_qualifier_ids;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001291 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -06001292 struct intlist *tid_list;
1293 struct intlist *pid_list;
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08001294 struct {
1295 size_t nr;
1296 pid_t *entries;
1297 } filter_pids;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001298 double duration_filter;
1299 double runtime_ms;
1300 struct {
1301 u64 vfs_getname,
1302 proc_getname;
1303 } stats;
1304 bool not_ev_qualifier;
1305 bool live;
1306 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001307 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001308 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001309 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001310 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001311 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001312 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001313 bool trace_syscalls;
Yunlong Songe366a6d2015-04-02 21:47:18 +08001314 bool force;
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03001315 bool vfs_getname;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001316 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001317};
1318
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001319static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001320{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001321 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001322
1323 if (fd > ttrace->paths.max) {
1324 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1325
1326 if (npath == NULL)
1327 return -1;
1328
1329 if (ttrace->paths.max != -1) {
1330 memset(npath + ttrace->paths.max + 1, 0,
1331 (fd - ttrace->paths.max) * sizeof(char *));
1332 } else {
1333 memset(npath, 0, (fd + 1) * sizeof(char *));
1334 }
1335
1336 ttrace->paths.table = npath;
1337 ttrace->paths.max = fd;
1338 }
1339
1340 ttrace->paths.table[fd] = strdup(pathname);
1341
1342 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1343}
1344
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001345static int thread__read_fd_path(struct thread *thread, int fd)
1346{
1347 char linkname[PATH_MAX], pathname[PATH_MAX];
1348 struct stat st;
1349 int ret;
1350
1351 if (thread->pid_ == thread->tid) {
1352 scnprintf(linkname, sizeof(linkname),
1353 "/proc/%d/fd/%d", thread->pid_, fd);
1354 } else {
1355 scnprintf(linkname, sizeof(linkname),
1356 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1357 }
1358
1359 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1360 return -1;
1361
1362 ret = readlink(linkname, pathname, sizeof(pathname));
1363
1364 if (ret < 0 || ret > st.st_size)
1365 return -1;
1366
1367 pathname[ret] = '\0';
1368 return trace__set_fd_pathname(thread, fd, pathname);
1369}
1370
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001371static const char *thread__fd_path(struct thread *thread, int fd,
1372 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001373{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001374 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001375
1376 if (ttrace == NULL)
1377 return NULL;
1378
1379 if (fd < 0)
1380 return NULL;
1381
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001382 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001383 if (!trace->live)
1384 return NULL;
1385 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001386 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001387 return NULL;
1388 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001389
1390 return ttrace->paths.table[fd];
1391}
1392
1393static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1394 struct syscall_arg *arg)
1395{
1396 int fd = arg->val;
1397 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001398 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001399
1400 if (path)
1401 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1402
1403 return printed;
1404}
1405
1406static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1407 struct syscall_arg *arg)
1408{
1409 int fd = arg->val;
1410 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001411 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001412
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001413 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1414 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001415
1416 return printed;
1417}
1418
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001419static bool trace__filter_duration(struct trace *trace, double t)
1420{
1421 return t < (trace->duration_filter * NSEC_PER_MSEC);
1422}
1423
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001424static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1425{
1426 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1427
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001428 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001429}
1430
Namhyung Kimf15eb532012-10-05 14:02:16 +09001431static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001432static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001433
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001434static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001435{
1436 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001437 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001438}
1439
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001440static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001441 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001442{
1443 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001444 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001445
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001446 if (trace->multiple_threads) {
1447 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001448 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001449 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001450 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001451
1452 return printed;
1453}
1454
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001455static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001456 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001457{
1458 int ret = 0;
1459
1460 switch (event->header.type) {
1461 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001462 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001463 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001464 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001465 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001466 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001467 break;
1468 }
1469
1470 return ret;
1471}
1472
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001473static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001474 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001475 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001476 struct machine *machine)
1477{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001478 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001479 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001480}
1481
1482static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1483{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001484 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001485
1486 if (err)
1487 return err;
1488
David Ahern8fb598e2013-09-28 13:13:00 -06001489 trace->host = machine__new_host();
1490 if (trace->host == NULL)
1491 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001492
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001493 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001494 return -errno;
1495
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001496 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001497 evlist->threads, trace__tool_process, false,
1498 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001499 if (err)
1500 symbol__exit();
1501
1502 return err;
1503}
1504
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001505static int syscall__set_arg_fmts(struct syscall *sc)
1506{
1507 struct format_field *field;
1508 int idx = 0;
1509
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001510 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001511 if (sc->arg_scnprintf == NULL)
1512 return -1;
1513
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001514 if (sc->fmt)
1515 sc->arg_parm = sc->fmt->arg_parm;
1516
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001517 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001518 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1519 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1520 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001521 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1522 ++idx;
1523 }
1524
1525 return 0;
1526}
1527
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001528static int trace__read_syscall_info(struct trace *trace, int id)
1529{
1530 char tp_name[128];
1531 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001532 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001533
1534 if (name == NULL)
1535 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001536
1537 if (id > trace->syscalls.max) {
1538 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1539
1540 if (nsyscalls == NULL)
1541 return -1;
1542
1543 if (trace->syscalls.max != -1) {
1544 memset(nsyscalls + trace->syscalls.max + 1, 0,
1545 (id - trace->syscalls.max) * sizeof(*sc));
1546 } else {
1547 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1548 }
1549
1550 trace->syscalls.table = nsyscalls;
1551 trace->syscalls.max = id;
1552 }
1553
1554 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001555 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001556
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001557 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001558
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001559 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001560 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001561
1562 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1563 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001564 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001565 }
1566
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001567 if (sc->tp_format == NULL)
1568 return -1;
1569
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001570 sc->args = sc->tp_format->format.fields;
1571 sc->nr_args = sc->tp_format->format.nr_fields;
1572 /* drop nr field - not relevant here; does not exist on older kernels */
1573 if (sc->args && strcmp(sc->args->name, "nr") == 0) {
1574 sc->args = sc->args->next;
1575 --sc->nr_args;
1576 }
1577
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001578 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1579
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001580 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001581}
1582
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001583static int trace__validate_ev_qualifier(struct trace *trace)
1584{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001585 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001586 struct str_node *pos;
1587
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001588 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1589 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1590 sizeof(trace->ev_qualifier_ids.entries[0]));
1591
1592 if (trace->ev_qualifier_ids.entries == NULL) {
1593 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1594 trace->output);
1595 err = -EINVAL;
1596 goto out;
1597 }
1598
1599 i = 0;
1600
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001601 strlist__for_each(pos, trace->ev_qualifier) {
1602 const char *sc = pos->s;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001603 int id = audit_name_to_syscall(sc, trace->audit.machine);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001604
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001605 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001606 if (err == 0) {
1607 fputs("Error:\tInvalid syscall ", trace->output);
1608 err = -EINVAL;
1609 } else {
1610 fputs(", ", trace->output);
1611 }
1612
1613 fputs(sc, trace->output);
1614 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001615
1616 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001617 }
1618
1619 if (err < 0) {
1620 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1621 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001622 zfree(&trace->ev_qualifier_ids.entries);
1623 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001624 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001625out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001626 return err;
1627}
1628
David Ahern55d43bc2015-02-19 15:00:22 -05001629/*
1630 * args is to be interpreted as a series of longs but we need to handle
1631 * 8-byte unaligned accesses. args points to raw_data within the event
1632 * and raw_data is guaranteed to be 8-byte unaligned because it is
1633 * preceded by raw_size which is a u32. So we need to copy args to a temp
1634 * variable to read it. Most notably this avoids extended load instructions
1635 * on unaligned addresses
1636 */
1637
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001638static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001639 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001640 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001641{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001642 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001643 unsigned char *p;
1644 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001645
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001646 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001647 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001648 u8 bit = 1;
1649 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001650 .idx = 0,
1651 .mask = 0,
1652 .trace = trace,
1653 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001654 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001655
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001656 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001657 field = field->next, ++arg.idx, bit <<= 1) {
1658 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001659 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001660
1661 /* special care for unaligned accesses */
1662 p = args + sizeof(unsigned long) * arg.idx;
1663 memcpy(&val, p, sizeof(val));
1664
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001665 /*
1666 * Suppress this argument if its value is zero and
1667 * and we don't have a string associated in an
1668 * strarray for it.
1669 */
David Ahern55d43bc2015-02-19 15:00:22 -05001670 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001671 !(sc->arg_scnprintf &&
1672 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1673 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001674 continue;
1675
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001676 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001677 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001678 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001679 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001680 if (sc->arg_parm)
1681 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001682 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1683 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001684 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001685 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001686 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001687 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001688 }
1689 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001690 int i = 0;
1691
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001692 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001693 /* special care for unaligned accesses */
1694 p = args + sizeof(unsigned long) * i;
1695 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001696 printed += scnprintf(bf + printed, size - printed,
1697 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001698 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001699 ++i;
1700 }
1701 }
1702
1703 return printed;
1704}
1705
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001706typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001707 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001708 struct perf_sample *sample);
1709
1710static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001711 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001712{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001713
1714 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001715
1716 /*
1717 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1718 * before that, leaving at a higher verbosity level till that is
1719 * explained. Reproduced with plain ftrace with:
1720 *
1721 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1722 * grep "NR -1 " /t/trace_pipe
1723 *
1724 * After generating some load on the machine.
1725 */
1726 if (verbose > 1) {
1727 static u64 n;
1728 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1729 id, perf_evsel__name(evsel), ++n);
1730 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001731 return NULL;
1732 }
1733
1734 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1735 trace__read_syscall_info(trace, id))
1736 goto out_cant_read;
1737
1738 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1739 goto out_cant_read;
1740
1741 return &trace->syscalls.table[id];
1742
1743out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001744 if (verbose) {
1745 fprintf(trace->output, "Problems reading syscall %d", id);
1746 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1747 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1748 fputs(" information\n", trace->output);
1749 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001750 return NULL;
1751}
1752
David Ahernbf2575c2013-10-08 21:26:53 -06001753static void thread__update_stats(struct thread_trace *ttrace,
1754 int id, struct perf_sample *sample)
1755{
1756 struct int_node *inode;
1757 struct stats *stats;
1758 u64 duration = 0;
1759
1760 inode = intlist__findnew(ttrace->syscall_stats, id);
1761 if (inode == NULL)
1762 return;
1763
1764 stats = inode->priv;
1765 if (stats == NULL) {
1766 stats = malloc(sizeof(struct stats));
1767 if (stats == NULL)
1768 return;
1769 init_stats(stats);
1770 inode->priv = stats;
1771 }
1772
1773 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1774 duration = sample->time - ttrace->entry_time;
1775
1776 update_stats(stats, duration);
1777}
1778
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001779static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1780{
1781 struct thread_trace *ttrace;
1782 u64 duration;
1783 size_t printed;
1784
1785 if (trace->current == NULL)
1786 return 0;
1787
1788 ttrace = thread__priv(trace->current);
1789
1790 if (!ttrace->entry_pending)
1791 return 0;
1792
1793 duration = sample->time - ttrace->entry_time;
1794
1795 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1796 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1797 ttrace->entry_pending = false;
1798
1799 return printed;
1800}
1801
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001802static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001803 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001804 struct perf_sample *sample)
1805{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001806 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001807 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001808 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001809 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001810 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001811 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001812 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001813
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001814 if (sc == NULL)
1815 return -1;
1816
David Ahern8fb598e2013-09-28 13:13:00 -06001817 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001818 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001819 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001820 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001821
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001822 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001823
1824 if (ttrace->entry_str == NULL) {
1825 ttrace->entry_str = malloc(1024);
1826 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001827 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001828 }
1829
David Ahern13f22a22015-03-19 12:23:03 -06001830 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001831 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001832
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001833 ttrace->entry_time = sample->time;
1834 msg = ttrace->entry_str;
1835 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1836
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001837 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1838 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001839
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001840 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001841 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001842 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1843 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001844 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001845 } else
1846 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001847
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001848 if (trace->current != thread) {
1849 thread__put(trace->current);
1850 trace->current = thread__get(thread);
1851 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001852 err = 0;
1853out_put:
1854 thread__put(thread);
1855 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001856}
1857
1858static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001859 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001860 struct perf_sample *sample)
1861{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001862 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001863 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001864 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001865 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001866 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001867 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001868
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001869 if (sc == NULL)
1870 return -1;
1871
David Ahern8fb598e2013-09-28 13:13:00 -06001872 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001873 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001874 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001875 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001876
David Ahernbf2575c2013-10-08 21:26:53 -06001877 if (trace->summary)
1878 thread__update_stats(ttrace, id, sample);
1879
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001880 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001881
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001882 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1883 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1884 trace->last_vfs_getname = NULL;
1885 ++trace->stats.vfs_getname;
1886 }
1887
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001888 ttrace->exit_time = sample->time;
1889
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001890 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001891 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001892 if (trace__filter_duration(trace, duration))
1893 goto out;
1894 } else if (trace->duration_filter)
1895 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001896
David Ahernfd2eaba2013-11-12 09:31:15 -07001897 if (trace->summary_only)
1898 goto out;
1899
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001900 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001901
1902 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001903 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001904 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001905 fprintf(trace->output, " ... [");
1906 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1907 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001908 }
1909
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001910 if (sc->fmt == NULL) {
1911signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001912 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001913 } else if (ret < 0 && sc->fmt->errmsg) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001914 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001915 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1916 *e = audit_errno_to_name(-ret);
1917
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001918 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001919 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001920 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001921 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001922 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001923 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001924 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001925
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001926 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001927out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001928 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001929 err = 0;
1930out_put:
1931 thread__put(thread);
1932 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001933}
1934
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001935static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001936 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001937 struct perf_sample *sample)
1938{
1939 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1940 return 0;
1941}
1942
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001943static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001944 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001945 struct perf_sample *sample)
1946{
1947 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1948 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001949 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001950 sample->pid,
1951 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001952 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001953
1954 if (ttrace == NULL)
1955 goto out_dump;
1956
1957 ttrace->runtime_ms += runtime_ms;
1958 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001959 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001960 return 0;
1961
1962out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001963 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001964 evsel->name,
1965 perf_evsel__strval(evsel, sample, "comm"),
1966 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1967 runtime,
1968 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001969 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001970 return 0;
1971}
1972
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001973static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1974 union perf_event *event __maybe_unused,
1975 struct perf_sample *sample)
1976{
1977 trace__printf_interrupted_entry(trace, sample);
1978 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001979
1980 if (trace->trace_syscalls)
1981 fprintf(trace->output, "( ): ");
1982
1983 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001984
1985 if (evsel->tp_format) {
1986 event_format__fprintf(evsel->tp_format, sample->cpu,
1987 sample->raw_data, sample->raw_size,
1988 trace->output);
1989 }
1990
1991 fprintf(trace->output, ")\n");
1992 return 0;
1993}
1994
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001995static void print_location(FILE *f, struct perf_sample *sample,
1996 struct addr_location *al,
1997 bool print_dso, bool print_sym)
1998{
1999
2000 if ((verbose || print_dso) && al->map)
2001 fprintf(f, "%s@", al->map->dso->long_name);
2002
2003 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002004 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002005 al->addr - al->sym->start);
2006 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002007 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002008 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002009 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002010}
2011
2012static int trace__pgfault(struct trace *trace,
2013 struct perf_evsel *evsel,
2014 union perf_event *event,
2015 struct perf_sample *sample)
2016{
2017 struct thread *thread;
2018 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
2019 struct addr_location al;
2020 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002021 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002022 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002023
2024 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002025 ttrace = thread__trace(thread, trace->output);
2026 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002027 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002028
2029 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2030 ttrace->pfmaj++;
2031 else
2032 ttrace->pfmin++;
2033
2034 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002035 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002036
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002037 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002038 sample->ip, &al);
2039
2040 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2041
2042 fprintf(trace->output, "%sfault [",
2043 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2044 "maj" : "min");
2045
2046 print_location(trace->output, sample, &al, false, true);
2047
2048 fprintf(trace->output, "] => ");
2049
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002050 thread__find_addr_location(thread, cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002051 sample->addr, &al);
2052
2053 if (!al.map) {
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002054 thread__find_addr_location(thread, cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002055 MAP__FUNCTION, sample->addr, &al);
2056
2057 if (al.map)
2058 map_type = 'x';
2059 else
2060 map_type = '?';
2061 }
2062
2063 print_location(trace->output, sample, &al, true, false);
2064
2065 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002066out:
2067 err = 0;
2068out_put:
2069 thread__put(thread);
2070 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002071}
2072
David Ahernbdc89662013-08-28 22:29:53 -06002073static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2074{
2075 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2076 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2077 return false;
2078
2079 if (trace->pid_list || trace->tid_list)
2080 return true;
2081
2082 return false;
2083}
2084
David Ahern6810fc92013-08-28 22:29:52 -06002085static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002086 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002087 struct perf_sample *sample,
2088 struct perf_evsel *evsel,
2089 struct machine *machine __maybe_unused)
2090{
2091 struct trace *trace = container_of(tool, struct trace, tool);
2092 int err = 0;
2093
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002094 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002095
David Ahernbdc89662013-08-28 22:29:53 -06002096 if (skip_sample(trace, sample))
2097 return 0;
2098
David Ahern4bb09192013-09-04 12:37:43 -06002099 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06002100 trace->base_time = sample->time;
2101
David Ahern31605652013-12-04 19:41:41 -07002102 if (handler) {
2103 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002104 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002105 }
David Ahern6810fc92013-08-28 22:29:52 -06002106
2107 return err;
2108}
2109
David Ahernbdc89662013-08-28 22:29:53 -06002110static int parse_target_str(struct trace *trace)
2111{
2112 if (trace->opts.target.pid) {
2113 trace->pid_list = intlist__new(trace->opts.target.pid);
2114 if (trace->pid_list == NULL) {
2115 pr_err("Error parsing process id string\n");
2116 return -EINVAL;
2117 }
2118 }
2119
2120 if (trace->opts.target.tid) {
2121 trace->tid_list = intlist__new(trace->opts.target.tid);
2122 if (trace->tid_list == NULL) {
2123 pr_err("Error parsing thread id string\n");
2124 return -EINVAL;
2125 }
2126 }
2127
2128 return 0;
2129}
2130
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002131static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002132{
2133 unsigned int rec_argc, i, j;
2134 const char **rec_argv;
2135 const char * const record_args[] = {
2136 "record",
2137 "-R",
2138 "-m", "1024",
2139 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002140 };
2141
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002142 const char * const sc_args[] = { "-e", };
2143 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2144 const char * const majpf_args[] = { "-e", "major-faults" };
2145 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2146 const char * const minpf_args[] = { "-e", "minor-faults" };
2147 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2148
David Ahern9aca7f12013-12-04 19:41:39 -07002149 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002150 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2151 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002152 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2153
2154 if (rec_argv == NULL)
2155 return -ENOMEM;
2156
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002157 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002158 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002159 rec_argv[j++] = record_args[i];
2160
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002161 if (trace->trace_syscalls) {
2162 for (i = 0; i < sc_args_nr; i++)
2163 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002164
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002165 /* event string may be different for older kernels - e.g., RHEL6 */
2166 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2167 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2168 else if (is_valid_tracepoint("syscalls:sys_enter"))
2169 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2170 else {
2171 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2172 return -1;
2173 }
David Ahern9aca7f12013-12-04 19:41:39 -07002174 }
David Ahern9aca7f12013-12-04 19:41:39 -07002175
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002176 if (trace->trace_pgfaults & TRACE_PFMAJ)
2177 for (i = 0; i < majpf_args_nr; i++)
2178 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002179
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002180 if (trace->trace_pgfaults & TRACE_PFMIN)
2181 for (i = 0; i < minpf_args_nr; i++)
2182 rec_argv[j++] = minpf_args[i];
2183
2184 for (i = 0; i < (unsigned int)argc; i++)
2185 rec_argv[j++] = argv[i];
2186
2187 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002188}
2189
David Ahernbf2575c2013-10-08 21:26:53 -06002190static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2191
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002192static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002193{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002194 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002195 if (evsel == NULL)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002196 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002197
2198 if (perf_evsel__field(evsel, "pathname") == NULL) {
2199 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002200 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002201 }
2202
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002203 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002204 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002205 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002206}
2207
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002208static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2209 u64 config)
2210{
2211 struct perf_evsel *evsel;
2212 struct perf_event_attr attr = {
2213 .type = PERF_TYPE_SOFTWARE,
2214 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002215 };
2216
2217 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002218 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002219
2220 event_attr_init(&attr);
2221
2222 evsel = perf_evsel__new(&attr);
2223 if (!evsel)
2224 return -ENOMEM;
2225
2226 evsel->handler = trace__pgfault;
2227 perf_evlist__add(evlist, evsel);
2228
2229 return 0;
2230}
2231
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002232static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2233{
2234 const u32 type = event->header.type;
2235 struct perf_evsel *evsel;
2236
2237 if (!trace->full_time && trace->base_time == 0)
2238 trace->base_time = sample->time;
2239
2240 if (type != PERF_RECORD_SAMPLE) {
2241 trace__process_event(trace, trace->host, event, sample);
2242 return;
2243 }
2244
2245 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2246 if (evsel == NULL) {
2247 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2248 return;
2249 }
2250
2251 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2252 sample->raw_data == NULL) {
2253 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2254 perf_evsel__name(evsel), sample->tid,
2255 sample->cpu, sample->raw_size);
2256 } else {
2257 tracepoint_handler handler = evsel->handler;
2258 handler(trace, evsel, event, sample);
2259 }
2260}
2261
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002262static int trace__add_syscall_newtp(struct trace *trace)
2263{
2264 int ret = -1;
2265 struct perf_evlist *evlist = trace->evlist;
2266 struct perf_evsel *sys_enter, *sys_exit;
2267
2268 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2269 if (sys_enter == NULL)
2270 goto out;
2271
2272 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2273 goto out_delete_sys_enter;
2274
2275 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2276 if (sys_exit == NULL)
2277 goto out_delete_sys_enter;
2278
2279 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2280 goto out_delete_sys_exit;
2281
2282 perf_evlist__add(evlist, sys_enter);
2283 perf_evlist__add(evlist, sys_exit);
2284
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002285 trace->syscalls.events.sys_enter = sys_enter;
2286 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002287
2288 ret = 0;
2289out:
2290 return ret;
2291
2292out_delete_sys_exit:
2293 perf_evsel__delete_priv(sys_exit);
2294out_delete_sys_enter:
2295 perf_evsel__delete_priv(sys_enter);
2296 goto out;
2297}
2298
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002299static int trace__set_ev_qualifier_filter(struct trace *trace)
2300{
2301 int err = -1;
2302 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2303 trace->ev_qualifier_ids.nr,
2304 trace->ev_qualifier_ids.entries);
2305
2306 if (filter == NULL)
2307 goto out_enomem;
2308
2309 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2310 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2311
2312 free(filter);
2313out:
2314 return err;
2315out_enomem:
2316 errno = ENOMEM;
2317 goto out;
2318}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002319
Namhyung Kimf15eb532012-10-05 14:02:16 +09002320static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002321{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002322 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002323 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002324 int err = -1, i;
2325 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002326 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002327 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002328
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002329 trace->live = true;
2330
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002331 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002332 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002333
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002334 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002335 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002336
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002337 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002338 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002339 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002340 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002341
2342 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2343 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002344 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002345
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002346 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002347 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2348 trace__sched_stat_runtime))
2349 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002350
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002351 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2352 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002353 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002354 goto out_delete_evlist;
2355 }
2356
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002357 err = trace__symbols_init(trace, evlist);
2358 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002359 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002360 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002361 }
2362
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002363 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002364
Namhyung Kimf15eb532012-10-05 14:02:16 +09002365 signal(SIGCHLD, sig_handler);
2366 signal(SIGINT, sig_handler);
2367
2368 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002369 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002370 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002371 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002372 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002373 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002374 }
2375 }
2376
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002377 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002378 if (err < 0)
2379 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002380
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002381 /*
2382 * Better not use !target__has_task() here because we need to cover the
2383 * case where no threads were specified in the command line, but a
2384 * workload was, and in that case we will fill in the thread_map when
2385 * we fork the workload in perf_evlist__prepare_workload.
2386 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002387 if (trace->filter_pids.nr > 0)
2388 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002389 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002390 err = perf_evlist__set_filter_pid(evlist, getpid());
2391
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002392 if (err < 0)
2393 goto out_error_mem;
2394
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002395 if (trace->ev_qualifier_ids.nr > 0) {
2396 err = trace__set_ev_qualifier_filter(trace);
2397 if (err < 0)
2398 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002399
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002400 pr_debug("event qualifier tracepoint filter: %s\n",
2401 trace->syscalls.events.sys_exit->filter);
2402 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002403
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002404 err = perf_evlist__apply_filters(evlist, &evsel);
2405 if (err < 0)
2406 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002407
Jiri Olsaf8850372013-11-28 17:57:22 +01002408 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002409 if (err < 0)
2410 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002411
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002412 if (!target__none(&trace->opts.target))
2413 perf_evlist__enable(evlist);
2414
Namhyung Kimf15eb532012-10-05 14:02:16 +09002415 if (forks)
2416 perf_evlist__start_workload(evlist);
2417
Jiri Olsae13798c2015-06-23 00:36:02 +02002418 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002419 evlist->threads->nr > 1 ||
2420 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002421again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002422 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002423
2424 for (i = 0; i < evlist->nr_mmaps; i++) {
2425 union perf_event *event;
2426
2427 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002428 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002429
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002430 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002431
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002432 err = perf_evlist__parse_sample(evlist, event, &sample);
2433 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002434 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002435 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002436 }
2437
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002438 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002439next_event:
2440 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002441
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002442 if (interrupted)
2443 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002444
2445 if (done && !draining) {
2446 perf_evlist__disable(evlist);
2447 draining = true;
2448 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002449 }
2450 }
2451
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002452 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002453 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002454
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002455 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2456 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2457 draining = true;
2458
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002459 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002460 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002461 } else {
2462 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002463 }
2464
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002465out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002466 thread__zput(trace->current);
2467
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002468 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002469
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002470 if (!err) {
2471 if (trace->summary)
2472 trace__fprintf_thread_summary(trace, trace->output);
2473
2474 if (trace->show_tool_stats) {
2475 fprintf(trace->output, "Stats:\n "
2476 " vfs_getname : %" PRIu64 "\n"
2477 " proc_getname: %" PRIu64 "\n",
2478 trace->stats.vfs_getname,
2479 trace->stats.proc_getname);
2480 }
2481 }
David Ahernbf2575c2013-10-08 21:26:53 -06002482
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002483out_delete_evlist:
2484 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002485 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002486 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002487 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002488{
2489 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002490
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002491out_error_sched_stat_runtime:
2492 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
2493 goto out_error;
2494
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002495out_error_raw_syscalls:
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002496 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002497 goto out_error;
2498
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002499out_error_mmap:
2500 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2501 goto out_error;
2502
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002503out_error_open:
2504 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2505
2506out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002507 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302508 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002509
2510out_error_apply_filters:
2511 fprintf(trace->output,
2512 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2513 evsel->filter, perf_evsel__name(evsel), errno,
2514 strerror_r(errno, errbuf, sizeof(errbuf)));
2515 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002516}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002517out_error_mem:
2518 fprintf(trace->output, "Not enough memory to run!\n");
2519 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002520
2521out_errno:
2522 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2523 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002524}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002525
David Ahern6810fc92013-08-28 22:29:52 -06002526static int trace__replay(struct trace *trace)
2527{
2528 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002529 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002530 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002531 struct perf_data_file file = {
2532 .path = input_name,
2533 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002534 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002535 };
David Ahern6810fc92013-08-28 22:29:52 -06002536 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002537 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002538 int err = -1;
2539
2540 trace->tool.sample = trace__process_sample;
2541 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002542 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002543 trace->tool.comm = perf_event__process_comm;
2544 trace->tool.exit = perf_event__process_exit;
2545 trace->tool.fork = perf_event__process_fork;
2546 trace->tool.attr = perf_event__process_attr;
2547 trace->tool.tracing_data = perf_event__process_tracing_data;
2548 trace->tool.build_id = perf_event__process_build_id;
2549
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002550 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002551 trace->tool.ordering_requires_timestamps = true;
2552
2553 /* add tid to output */
2554 trace->multiple_threads = true;
2555
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002556 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002557 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002558 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002559
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002560 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002561 goto out;
2562
David Ahern8fb598e2013-09-28 13:13:00 -06002563 trace->host = &session->machines.host;
2564
David Ahern6810fc92013-08-28 22:29:52 -06002565 err = perf_session__set_tracepoints_handlers(session, handlers);
2566 if (err)
2567 goto out;
2568
Namhyung Kim003824e2013-11-12 15:25:00 +09002569 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2570 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002571 /* older kernels have syscalls tp versus raw_syscalls */
2572 if (evsel == NULL)
2573 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2574 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002575
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002576 if (evsel &&
2577 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2578 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002579 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2580 goto out;
2581 }
2582
2583 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2584 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002585 if (evsel == NULL)
2586 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2587 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002588 if (evsel &&
2589 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2590 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002591 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002592 goto out;
2593 }
2594
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002595 evlist__for_each(session->evlist, evsel) {
2596 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2597 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2598 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2599 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2600 evsel->handler = trace__pgfault;
2601 }
2602
David Ahernbdc89662013-08-28 22:29:53 -06002603 err = parse_target_str(trace);
2604 if (err != 0)
2605 goto out;
2606
David Ahern6810fc92013-08-28 22:29:52 -06002607 setup_pager();
2608
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002609 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002610 if (err)
2611 pr_err("Failed to process events, error %d", err);
2612
David Ahernbf2575c2013-10-08 21:26:53 -06002613 else if (trace->summary)
2614 trace__fprintf_thread_summary(trace, trace->output);
2615
David Ahern6810fc92013-08-28 22:29:52 -06002616out:
2617 perf_session__delete(session);
2618
2619 return err;
2620}
2621
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002622static size_t trace__fprintf_threads_header(FILE *fp)
2623{
2624 size_t printed;
2625
Pekka Enberg99ff7152013-11-12 16:42:14 +02002626 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002627
2628 return printed;
2629}
2630
2631static size_t thread__dump_stats(struct thread_trace *ttrace,
2632 struct trace *trace, FILE *fp)
2633{
2634 struct stats *stats;
2635 size_t printed = 0;
2636 struct syscall *sc;
2637 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2638
2639 if (inode == NULL)
2640 return 0;
2641
2642 printed += fprintf(fp, "\n");
2643
Pekka Enberg27a778b2013-11-13 14:21:48 +02002644 printed += fprintf(fp, " syscall calls min avg max stddev\n");
2645 printed += fprintf(fp, " (msec) (msec) (msec) (%%)\n");
2646 printed += fprintf(fp, " --------------- -------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002647
David Ahernbf2575c2013-10-08 21:26:53 -06002648 /* each int_node is a syscall */
2649 while (inode) {
2650 stats = inode->priv;
2651 if (stats) {
2652 double min = (double)(stats->min) / NSEC_PER_MSEC;
2653 double max = (double)(stats->max) / NSEC_PER_MSEC;
2654 double avg = avg_stats(stats);
2655 double pct;
2656 u64 n = (u64) stats->n;
2657
2658 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2659 avg /= NSEC_PER_MSEC;
2660
2661 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002662 printed += fprintf(fp, " %-15s", sc->name);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002663 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f",
Pekka Enberg7f7a4132013-11-12 16:10:10 +02002664 n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002665 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002666 }
2667
2668 inode = intlist__next(inode);
2669 }
2670
2671 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002672
2673 return printed;
2674}
2675
David Ahern896cbb52013-09-28 13:12:59 -06002676/* struct used to pass data to per-thread function */
2677struct summary_data {
2678 FILE *fp;
2679 struct trace *trace;
2680 size_t printed;
2681};
2682
2683static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2684{
2685 struct summary_data *data = priv;
2686 FILE *fp = data->fp;
2687 size_t printed = data->printed;
2688 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002689 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002690 double ratio;
2691
2692 if (ttrace == NULL)
2693 return 0;
2694
2695 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2696
Pekka Enberg15e65c62013-11-14 18:43:30 +02002697 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002698 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002699 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002700 if (ttrace->pfmaj)
2701 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2702 if (ttrace->pfmin)
2703 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002704 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002705 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002706
2707 data->printed += printed;
2708
2709 return 0;
2710}
2711
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002712static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2713{
David Ahern896cbb52013-09-28 13:12:59 -06002714 struct summary_data data = {
2715 .fp = fp,
2716 .trace = trace
2717 };
2718 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002719
David Ahern896cbb52013-09-28 13:12:59 -06002720 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002721
David Ahern896cbb52013-09-28 13:12:59 -06002722 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002723}
2724
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002725static int trace__set_duration(const struct option *opt, const char *str,
2726 int unset __maybe_unused)
2727{
2728 struct trace *trace = opt->value;
2729
2730 trace->duration_filter = atof(str);
2731 return 0;
2732}
2733
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002734static int trace__set_filter_pids(const struct option *opt, const char *str,
2735 int unset __maybe_unused)
2736{
2737 int ret = -1;
2738 size_t i;
2739 struct trace *trace = opt->value;
2740 /*
2741 * FIXME: introduce a intarray class, plain parse csv and create a
2742 * { int nr, int entries[] } struct...
2743 */
2744 struct intlist *list = intlist__new(str);
2745
2746 if (list == NULL)
2747 return -1;
2748
2749 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2750 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2751
2752 if (trace->filter_pids.entries == NULL)
2753 goto out;
2754
2755 trace->filter_pids.entries[0] = getpid();
2756
2757 for (i = 1; i < trace->filter_pids.nr; ++i)
2758 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2759
2760 intlist__delete(list);
2761 ret = 0;
2762out:
2763 return ret;
2764}
2765
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002766static int trace__open_output(struct trace *trace, const char *filename)
2767{
2768 struct stat st;
2769
2770 if (!stat(filename, &st) && st.st_size) {
2771 char oldname[PATH_MAX];
2772
2773 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2774 unlink(oldname);
2775 rename(filename, oldname);
2776 }
2777
2778 trace->output = fopen(filename, "w");
2779
2780 return trace->output == NULL ? -errno : 0;
2781}
2782
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002783static int parse_pagefaults(const struct option *opt, const char *str,
2784 int unset __maybe_unused)
2785{
2786 int *trace_pgfaults = opt->value;
2787
2788 if (strcmp(str, "all") == 0)
2789 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2790 else if (strcmp(str, "maj") == 0)
2791 *trace_pgfaults |= TRACE_PFMAJ;
2792 else if (strcmp(str, "min") == 0)
2793 *trace_pgfaults |= TRACE_PFMIN;
2794 else
2795 return -1;
2796
2797 return 0;
2798}
2799
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002800static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2801{
2802 struct perf_evsel *evsel;
2803
2804 evlist__for_each(evlist, evsel)
2805 evsel->handler = handler;
2806}
2807
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002808int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2809{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002810 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002811 "perf trace [<options>] [<command>]",
2812 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002813 "perf trace record [<options>] [<command>]",
2814 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002815 NULL
2816 };
2817 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002818 .audit = {
2819 .machine = audit_detect_machine(),
2820 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2821 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002822 .syscalls = {
2823 . max = -1,
2824 },
2825 .opts = {
2826 .target = {
2827 .uid = UINT_MAX,
2828 .uses_mmap = true,
2829 },
2830 .user_freq = UINT_MAX,
2831 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002832 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002833 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002834 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002835 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002836 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002837 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002838 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002839 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002840 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002841 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002842 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002843 OPT_CALLBACK(0, "event", &trace.evlist, "event",
2844 "event selector. use 'perf list' to list available events",
2845 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002846 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2847 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002848 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03002849 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002850 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002851 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002852 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2853 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002854 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002855 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002856 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2857 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002858 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002859 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002860 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002861 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002862 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002863 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002864 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2865 "number of mmap data pages",
2866 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002867 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002868 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002869 OPT_CALLBACK(0, "duration", &trace, "float",
2870 "show only events with duration > N.M ms",
2871 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002872 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002873 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002874 OPT_BOOLEAN('T', "time", &trace.full_time,
2875 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002876 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2877 "Show only syscall summary with statistics"),
2878 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2879 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002880 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2881 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002882 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002883 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Kan Liang9d9cad72015-06-17 09:51:11 -04002884 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2885 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002886 OPT_END()
2887 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002888 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002889 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002890 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002891
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002892 signal(SIGSEGV, sighandler_dump_stack);
2893 signal(SIGFPE, sighandler_dump_stack);
2894
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002895 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002896
2897 if (trace.evlist == NULL) {
2898 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002899 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002900 goto out;
2901 }
2902
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002903 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2904 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002905
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002906 if (trace.trace_pgfaults) {
2907 trace.opts.sample_address = true;
2908 trace.opts.sample_time = true;
2909 }
2910
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002911 if (trace.evlist->nr_entries > 0)
2912 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2913
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002914 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2915 return trace__record(&trace, argc-1, &argv[1]);
2916
2917 /* summary_only implies summary option, but don't overwrite summary if set */
2918 if (trace.summary_only)
2919 trace.summary = trace.summary_only;
2920
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002921 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2922 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002923 pr_err("Please specify something to trace.\n");
2924 return -1;
2925 }
2926
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002927 if (output_name != NULL) {
2928 err = trace__open_output(&trace, output_name);
2929 if (err < 0) {
2930 perror("failed to create output file");
2931 goto out;
2932 }
2933 }
2934
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002935 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002936 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03002937 struct strlist_config slist_config = {
2938 .dirname = system_path(STRACE_GROUPS_DIR),
2939 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002940
2941 trace.not_ev_qualifier = *s == '!';
2942 if (trace.not_ev_qualifier)
2943 ++s;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03002944 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002945 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002946 fputs("Not enough memory to parse event qualifier",
2947 trace.output);
2948 err = -ENOMEM;
2949 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002950 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03002951
2952 err = trace__validate_ev_qualifier(&trace);
2953 if (err)
2954 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002955 }
2956
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002957 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002958 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002959 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002960 fprintf(trace.output, "%s", bf);
2961 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002962 }
2963
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002964 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002965 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002966 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002967 fprintf(trace.output, "%s", bf);
2968 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002969 }
2970
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002971 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002972 trace.opts.target.system_wide = true;
2973
David Ahern6810fc92013-08-28 22:29:52 -06002974 if (input_name)
2975 err = trace__replay(&trace);
2976 else
2977 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002978
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002979out_close:
2980 if (output_name != NULL)
2981 fclose(trace.output);
2982out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002983 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002984}