blob: 12d6fc0227b1aa019cf5f1e831f2fcd81352cce4 [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 Meloe4d44e82015-08-04 22:17:29 -03001265static const size_t trace__entry_str_size = 2048;
1266
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001267struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001268 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001269 struct {
1270 int machine;
1271 int open_id;
1272 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001273 struct {
1274 int max;
1275 struct syscall *table;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001276 struct {
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001277 struct perf_evsel *sys_enter,
1278 *sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001279 } events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001280 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001281 struct record_opts opts;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001282 struct perf_evlist *evlist;
David Ahern8fb598e2013-09-28 13:13:00 -06001283 struct machine *host;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001284 struct thread *current;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001285 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001286 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001287 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001288 struct strlist *ev_qualifier;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001289 struct {
1290 size_t nr;
1291 int *entries;
1292 } ev_qualifier_ids;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001293 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -06001294 struct intlist *tid_list;
1295 struct intlist *pid_list;
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08001296 struct {
1297 size_t nr;
1298 pid_t *entries;
1299 } filter_pids;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001300 double duration_filter;
1301 double runtime_ms;
1302 struct {
1303 u64 vfs_getname,
1304 proc_getname;
1305 } stats;
1306 bool not_ev_qualifier;
1307 bool live;
1308 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001309 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001310 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001311 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001312 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001313 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001314 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001315 bool trace_syscalls;
Yunlong Songe366a6d2015-04-02 21:47:18 +08001316 bool force;
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03001317 bool vfs_getname;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001318 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001319};
1320
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001321static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001322{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001323 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001324
1325 if (fd > ttrace->paths.max) {
1326 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1327
1328 if (npath == NULL)
1329 return -1;
1330
1331 if (ttrace->paths.max != -1) {
1332 memset(npath + ttrace->paths.max + 1, 0,
1333 (fd - ttrace->paths.max) * sizeof(char *));
1334 } else {
1335 memset(npath, 0, (fd + 1) * sizeof(char *));
1336 }
1337
1338 ttrace->paths.table = npath;
1339 ttrace->paths.max = fd;
1340 }
1341
1342 ttrace->paths.table[fd] = strdup(pathname);
1343
1344 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1345}
1346
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001347static int thread__read_fd_path(struct thread *thread, int fd)
1348{
1349 char linkname[PATH_MAX], pathname[PATH_MAX];
1350 struct stat st;
1351 int ret;
1352
1353 if (thread->pid_ == thread->tid) {
1354 scnprintf(linkname, sizeof(linkname),
1355 "/proc/%d/fd/%d", thread->pid_, fd);
1356 } else {
1357 scnprintf(linkname, sizeof(linkname),
1358 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1359 }
1360
1361 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1362 return -1;
1363
1364 ret = readlink(linkname, pathname, sizeof(pathname));
1365
1366 if (ret < 0 || ret > st.st_size)
1367 return -1;
1368
1369 pathname[ret] = '\0';
1370 return trace__set_fd_pathname(thread, fd, pathname);
1371}
1372
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001373static const char *thread__fd_path(struct thread *thread, int fd,
1374 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001375{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001376 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001377
1378 if (ttrace == NULL)
1379 return NULL;
1380
1381 if (fd < 0)
1382 return NULL;
1383
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001384 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001385 if (!trace->live)
1386 return NULL;
1387 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001388 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001389 return NULL;
1390 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001391
1392 return ttrace->paths.table[fd];
1393}
1394
1395static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1396 struct syscall_arg *arg)
1397{
1398 int fd = arg->val;
1399 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001400 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001401
1402 if (path)
1403 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1404
1405 return printed;
1406}
1407
1408static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1409 struct syscall_arg *arg)
1410{
1411 int fd = arg->val;
1412 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001413 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001414
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001415 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1416 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001417
1418 return printed;
1419}
1420
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001421static bool trace__filter_duration(struct trace *trace, double t)
1422{
1423 return t < (trace->duration_filter * NSEC_PER_MSEC);
1424}
1425
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001426static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1427{
1428 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1429
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001430 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001431}
1432
Namhyung Kimf15eb532012-10-05 14:02:16 +09001433static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001434static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001435
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001436static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001437{
1438 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001439 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001440}
1441
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001442static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001443 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001444{
1445 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001446 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001447
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001448 if (trace->multiple_threads) {
1449 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001450 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001451 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001452 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001453
1454 return printed;
1455}
1456
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001457static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001458 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001459{
1460 int ret = 0;
1461
1462 switch (event->header.type) {
1463 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001464 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001465 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001466 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001467 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001468 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001469 break;
1470 }
1471
1472 return ret;
1473}
1474
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001475static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001476 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001477 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001478 struct machine *machine)
1479{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001480 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001481 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001482}
1483
1484static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1485{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001486 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001487
1488 if (err)
1489 return err;
1490
David Ahern8fb598e2013-09-28 13:13:00 -06001491 trace->host = machine__new_host();
1492 if (trace->host == NULL)
1493 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001494
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001495 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001496 return -errno;
1497
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001498 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001499 evlist->threads, trace__tool_process, false,
1500 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001501 if (err)
1502 symbol__exit();
1503
1504 return err;
1505}
1506
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001507static int syscall__set_arg_fmts(struct syscall *sc)
1508{
1509 struct format_field *field;
1510 int idx = 0;
1511
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001512 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001513 if (sc->arg_scnprintf == NULL)
1514 return -1;
1515
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001516 if (sc->fmt)
1517 sc->arg_parm = sc->fmt->arg_parm;
1518
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001519 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001520 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1521 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1522 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001523 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1524 ++idx;
1525 }
1526
1527 return 0;
1528}
1529
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001530static int trace__read_syscall_info(struct trace *trace, int id)
1531{
1532 char tp_name[128];
1533 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001534 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001535
1536 if (name == NULL)
1537 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001538
1539 if (id > trace->syscalls.max) {
1540 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1541
1542 if (nsyscalls == NULL)
1543 return -1;
1544
1545 if (trace->syscalls.max != -1) {
1546 memset(nsyscalls + trace->syscalls.max + 1, 0,
1547 (id - trace->syscalls.max) * sizeof(*sc));
1548 } else {
1549 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1550 }
1551
1552 trace->syscalls.table = nsyscalls;
1553 trace->syscalls.max = id;
1554 }
1555
1556 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001557 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001558
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001559 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001560
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001561 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001562 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001563
1564 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1565 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001566 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001567 }
1568
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001569 if (sc->tp_format == NULL)
1570 return -1;
1571
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001572 sc->args = sc->tp_format->format.fields;
1573 sc->nr_args = sc->tp_format->format.nr_fields;
1574 /* drop nr field - not relevant here; does not exist on older kernels */
1575 if (sc->args && strcmp(sc->args->name, "nr") == 0) {
1576 sc->args = sc->args->next;
1577 --sc->nr_args;
1578 }
1579
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001580 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1581
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001582 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001583}
1584
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001585static int trace__validate_ev_qualifier(struct trace *trace)
1586{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001587 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001588 struct str_node *pos;
1589
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001590 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1591 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1592 sizeof(trace->ev_qualifier_ids.entries[0]));
1593
1594 if (trace->ev_qualifier_ids.entries == NULL) {
1595 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1596 trace->output);
1597 err = -EINVAL;
1598 goto out;
1599 }
1600
1601 i = 0;
1602
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001603 strlist__for_each(pos, trace->ev_qualifier) {
1604 const char *sc = pos->s;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001605 int id = audit_name_to_syscall(sc, trace->audit.machine);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001606
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001607 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001608 if (err == 0) {
1609 fputs("Error:\tInvalid syscall ", trace->output);
1610 err = -EINVAL;
1611 } else {
1612 fputs(", ", trace->output);
1613 }
1614
1615 fputs(sc, trace->output);
1616 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001617
1618 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001619 }
1620
1621 if (err < 0) {
1622 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1623 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001624 zfree(&trace->ev_qualifier_ids.entries);
1625 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001626 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001627out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001628 return err;
1629}
1630
David Ahern55d43bc2015-02-19 15:00:22 -05001631/*
1632 * args is to be interpreted as a series of longs but we need to handle
1633 * 8-byte unaligned accesses. args points to raw_data within the event
1634 * and raw_data is guaranteed to be 8-byte unaligned because it is
1635 * preceded by raw_size which is a u32. So we need to copy args to a temp
1636 * variable to read it. Most notably this avoids extended load instructions
1637 * on unaligned addresses
1638 */
1639
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001640static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001641 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001642 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001643{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001644 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001645 unsigned char *p;
1646 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001647
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001648 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001649 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001650 u8 bit = 1;
1651 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001652 .idx = 0,
1653 .mask = 0,
1654 .trace = trace,
1655 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001656 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001657
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001658 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001659 field = field->next, ++arg.idx, bit <<= 1) {
1660 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001661 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001662
1663 /* special care for unaligned accesses */
1664 p = args + sizeof(unsigned long) * arg.idx;
1665 memcpy(&val, p, sizeof(val));
1666
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001667 /*
1668 * Suppress this argument if its value is zero and
1669 * and we don't have a string associated in an
1670 * strarray for it.
1671 */
David Ahern55d43bc2015-02-19 15:00:22 -05001672 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001673 !(sc->arg_scnprintf &&
1674 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1675 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001676 continue;
1677
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001678 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001679 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001680 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001681 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001682 if (sc->arg_parm)
1683 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001684 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1685 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001686 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001687 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001688 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001689 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001690 }
1691 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001692 int i = 0;
1693
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001694 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001695 /* special care for unaligned accesses */
1696 p = args + sizeof(unsigned long) * i;
1697 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001698 printed += scnprintf(bf + printed, size - printed,
1699 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001700 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001701 ++i;
1702 }
1703 }
1704
1705 return printed;
1706}
1707
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001708typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001709 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001710 struct perf_sample *sample);
1711
1712static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001713 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001714{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001715
1716 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001717
1718 /*
1719 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1720 * before that, leaving at a higher verbosity level till that is
1721 * explained. Reproduced with plain ftrace with:
1722 *
1723 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1724 * grep "NR -1 " /t/trace_pipe
1725 *
1726 * After generating some load on the machine.
1727 */
1728 if (verbose > 1) {
1729 static u64 n;
1730 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1731 id, perf_evsel__name(evsel), ++n);
1732 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001733 return NULL;
1734 }
1735
1736 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1737 trace__read_syscall_info(trace, id))
1738 goto out_cant_read;
1739
1740 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1741 goto out_cant_read;
1742
1743 return &trace->syscalls.table[id];
1744
1745out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001746 if (verbose) {
1747 fprintf(trace->output, "Problems reading syscall %d", id);
1748 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1749 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1750 fputs(" information\n", trace->output);
1751 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001752 return NULL;
1753}
1754
David Ahernbf2575c2013-10-08 21:26:53 -06001755static void thread__update_stats(struct thread_trace *ttrace,
1756 int id, struct perf_sample *sample)
1757{
1758 struct int_node *inode;
1759 struct stats *stats;
1760 u64 duration = 0;
1761
1762 inode = intlist__findnew(ttrace->syscall_stats, id);
1763 if (inode == NULL)
1764 return;
1765
1766 stats = inode->priv;
1767 if (stats == NULL) {
1768 stats = malloc(sizeof(struct stats));
1769 if (stats == NULL)
1770 return;
1771 init_stats(stats);
1772 inode->priv = stats;
1773 }
1774
1775 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1776 duration = sample->time - ttrace->entry_time;
1777
1778 update_stats(stats, duration);
1779}
1780
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001781static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1782{
1783 struct thread_trace *ttrace;
1784 u64 duration;
1785 size_t printed;
1786
1787 if (trace->current == NULL)
1788 return 0;
1789
1790 ttrace = thread__priv(trace->current);
1791
1792 if (!ttrace->entry_pending)
1793 return 0;
1794
1795 duration = sample->time - ttrace->entry_time;
1796
1797 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1798 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1799 ttrace->entry_pending = false;
1800
1801 return printed;
1802}
1803
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001804static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001805 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001806 struct perf_sample *sample)
1807{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001808 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001809 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001810 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001811 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001812 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001813 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001814 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001815
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001816 if (sc == NULL)
1817 return -1;
1818
David Ahern8fb598e2013-09-28 13:13:00 -06001819 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001820 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001821 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001822 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001823
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001824 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001825
1826 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001827 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001828 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001829 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001830 }
1831
David Ahern13f22a22015-03-19 12:23:03 -06001832 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001833 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001834
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001835 ttrace->entry_time = sample->time;
1836 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001837 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001838
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001839 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001840 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001841
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001842 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001843 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001844 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1845 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001846 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001847 } else
1848 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001849
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001850 if (trace->current != thread) {
1851 thread__put(trace->current);
1852 trace->current = thread__get(thread);
1853 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001854 err = 0;
1855out_put:
1856 thread__put(thread);
1857 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001858}
1859
1860static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001861 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001862 struct perf_sample *sample)
1863{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001864 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001865 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001866 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001867 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001868 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001869 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001870
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001871 if (sc == NULL)
1872 return -1;
1873
David Ahern8fb598e2013-09-28 13:13:00 -06001874 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001875 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001876 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001877 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001878
David Ahernbf2575c2013-10-08 21:26:53 -06001879 if (trace->summary)
1880 thread__update_stats(ttrace, id, sample);
1881
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001882 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001883
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001884 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1885 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1886 trace->last_vfs_getname = NULL;
1887 ++trace->stats.vfs_getname;
1888 }
1889
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001890 ttrace->exit_time = sample->time;
1891
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001892 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001893 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001894 if (trace__filter_duration(trace, duration))
1895 goto out;
1896 } else if (trace->duration_filter)
1897 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001898
David Ahernfd2eaba2013-11-12 09:31:15 -07001899 if (trace->summary_only)
1900 goto out;
1901
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001902 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001903
1904 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001905 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001906 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001907 fprintf(trace->output, " ... [");
1908 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1909 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001910 }
1911
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001912 if (sc->fmt == NULL) {
1913signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001914 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001915 } else if (ret < 0 && sc->fmt->errmsg) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001916 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001917 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1918 *e = audit_errno_to_name(-ret);
1919
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001920 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001921 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001922 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001923 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001924 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001925 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001926 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001927
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001928 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001929out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001930 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001931 err = 0;
1932out_put:
1933 thread__put(thread);
1934 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001935}
1936
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001937static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001938 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001939 struct perf_sample *sample)
1940{
1941 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1942 return 0;
1943}
1944
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001945static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001946 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001947 struct perf_sample *sample)
1948{
1949 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1950 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001951 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001952 sample->pid,
1953 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001954 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001955
1956 if (ttrace == NULL)
1957 goto out_dump;
1958
1959 ttrace->runtime_ms += runtime_ms;
1960 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001961 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001962 return 0;
1963
1964out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001965 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001966 evsel->name,
1967 perf_evsel__strval(evsel, sample, "comm"),
1968 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1969 runtime,
1970 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001971 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001972 return 0;
1973}
1974
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001975static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1976 union perf_event *event __maybe_unused,
1977 struct perf_sample *sample)
1978{
1979 trace__printf_interrupted_entry(trace, sample);
1980 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001981
1982 if (trace->trace_syscalls)
1983 fprintf(trace->output, "( ): ");
1984
1985 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001986
1987 if (evsel->tp_format) {
1988 event_format__fprintf(evsel->tp_format, sample->cpu,
1989 sample->raw_data, sample->raw_size,
1990 trace->output);
1991 }
1992
1993 fprintf(trace->output, ")\n");
1994 return 0;
1995}
1996
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001997static void print_location(FILE *f, struct perf_sample *sample,
1998 struct addr_location *al,
1999 bool print_dso, bool print_sym)
2000{
2001
2002 if ((verbose || print_dso) && al->map)
2003 fprintf(f, "%s@", al->map->dso->long_name);
2004
2005 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002006 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002007 al->addr - al->sym->start);
2008 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002009 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002010 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002011 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002012}
2013
2014static int trace__pgfault(struct trace *trace,
2015 struct perf_evsel *evsel,
2016 union perf_event *event,
2017 struct perf_sample *sample)
2018{
2019 struct thread *thread;
2020 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
2021 struct addr_location al;
2022 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002023 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002024 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002025
2026 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002027 ttrace = thread__trace(thread, trace->output);
2028 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002029 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002030
2031 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2032 ttrace->pfmaj++;
2033 else
2034 ttrace->pfmin++;
2035
2036 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002037 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002038
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002039 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002040 sample->ip, &al);
2041
2042 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2043
2044 fprintf(trace->output, "%sfault [",
2045 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2046 "maj" : "min");
2047
2048 print_location(trace->output, sample, &al, false, true);
2049
2050 fprintf(trace->output, "] => ");
2051
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002052 thread__find_addr_location(thread, cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002053 sample->addr, &al);
2054
2055 if (!al.map) {
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002056 thread__find_addr_location(thread, cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002057 MAP__FUNCTION, sample->addr, &al);
2058
2059 if (al.map)
2060 map_type = 'x';
2061 else
2062 map_type = '?';
2063 }
2064
2065 print_location(trace->output, sample, &al, true, false);
2066
2067 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002068out:
2069 err = 0;
2070out_put:
2071 thread__put(thread);
2072 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002073}
2074
David Ahernbdc89662013-08-28 22:29:53 -06002075static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2076{
2077 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2078 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2079 return false;
2080
2081 if (trace->pid_list || trace->tid_list)
2082 return true;
2083
2084 return false;
2085}
2086
David Ahern6810fc92013-08-28 22:29:52 -06002087static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002088 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002089 struct perf_sample *sample,
2090 struct perf_evsel *evsel,
2091 struct machine *machine __maybe_unused)
2092{
2093 struct trace *trace = container_of(tool, struct trace, tool);
2094 int err = 0;
2095
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002096 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002097
David Ahernbdc89662013-08-28 22:29:53 -06002098 if (skip_sample(trace, sample))
2099 return 0;
2100
David Ahern4bb09192013-09-04 12:37:43 -06002101 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06002102 trace->base_time = sample->time;
2103
David Ahern31605652013-12-04 19:41:41 -07002104 if (handler) {
2105 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002106 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002107 }
David Ahern6810fc92013-08-28 22:29:52 -06002108
2109 return err;
2110}
2111
David Ahernbdc89662013-08-28 22:29:53 -06002112static int parse_target_str(struct trace *trace)
2113{
2114 if (trace->opts.target.pid) {
2115 trace->pid_list = intlist__new(trace->opts.target.pid);
2116 if (trace->pid_list == NULL) {
2117 pr_err("Error parsing process id string\n");
2118 return -EINVAL;
2119 }
2120 }
2121
2122 if (trace->opts.target.tid) {
2123 trace->tid_list = intlist__new(trace->opts.target.tid);
2124 if (trace->tid_list == NULL) {
2125 pr_err("Error parsing thread id string\n");
2126 return -EINVAL;
2127 }
2128 }
2129
2130 return 0;
2131}
2132
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002133static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002134{
2135 unsigned int rec_argc, i, j;
2136 const char **rec_argv;
2137 const char * const record_args[] = {
2138 "record",
2139 "-R",
2140 "-m", "1024",
2141 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002142 };
2143
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002144 const char * const sc_args[] = { "-e", };
2145 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2146 const char * const majpf_args[] = { "-e", "major-faults" };
2147 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2148 const char * const minpf_args[] = { "-e", "minor-faults" };
2149 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2150
David Ahern9aca7f12013-12-04 19:41:39 -07002151 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002152 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2153 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002154 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2155
2156 if (rec_argv == NULL)
2157 return -ENOMEM;
2158
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002159 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002160 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002161 rec_argv[j++] = record_args[i];
2162
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002163 if (trace->trace_syscalls) {
2164 for (i = 0; i < sc_args_nr; i++)
2165 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002166
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002167 /* event string may be different for older kernels - e.g., RHEL6 */
2168 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2169 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2170 else if (is_valid_tracepoint("syscalls:sys_enter"))
2171 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2172 else {
2173 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2174 return -1;
2175 }
David Ahern9aca7f12013-12-04 19:41:39 -07002176 }
David Ahern9aca7f12013-12-04 19:41:39 -07002177
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002178 if (trace->trace_pgfaults & TRACE_PFMAJ)
2179 for (i = 0; i < majpf_args_nr; i++)
2180 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002181
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002182 if (trace->trace_pgfaults & TRACE_PFMIN)
2183 for (i = 0; i < minpf_args_nr; i++)
2184 rec_argv[j++] = minpf_args[i];
2185
2186 for (i = 0; i < (unsigned int)argc; i++)
2187 rec_argv[j++] = argv[i];
2188
2189 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002190}
2191
David Ahernbf2575c2013-10-08 21:26:53 -06002192static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2193
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002194static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002195{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002196 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002197 if (evsel == NULL)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002198 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002199
2200 if (perf_evsel__field(evsel, "pathname") == NULL) {
2201 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002202 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002203 }
2204
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002205 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002206 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002207 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002208}
2209
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002210static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2211 u64 config)
2212{
2213 struct perf_evsel *evsel;
2214 struct perf_event_attr attr = {
2215 .type = PERF_TYPE_SOFTWARE,
2216 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002217 };
2218
2219 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002220 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002221
2222 event_attr_init(&attr);
2223
2224 evsel = perf_evsel__new(&attr);
2225 if (!evsel)
2226 return -ENOMEM;
2227
2228 evsel->handler = trace__pgfault;
2229 perf_evlist__add(evlist, evsel);
2230
2231 return 0;
2232}
2233
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002234static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2235{
2236 const u32 type = event->header.type;
2237 struct perf_evsel *evsel;
2238
2239 if (!trace->full_time && trace->base_time == 0)
2240 trace->base_time = sample->time;
2241
2242 if (type != PERF_RECORD_SAMPLE) {
2243 trace__process_event(trace, trace->host, event, sample);
2244 return;
2245 }
2246
2247 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2248 if (evsel == NULL) {
2249 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2250 return;
2251 }
2252
2253 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2254 sample->raw_data == NULL) {
2255 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2256 perf_evsel__name(evsel), sample->tid,
2257 sample->cpu, sample->raw_size);
2258 } else {
2259 tracepoint_handler handler = evsel->handler;
2260 handler(trace, evsel, event, sample);
2261 }
2262}
2263
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002264static int trace__add_syscall_newtp(struct trace *trace)
2265{
2266 int ret = -1;
2267 struct perf_evlist *evlist = trace->evlist;
2268 struct perf_evsel *sys_enter, *sys_exit;
2269
2270 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2271 if (sys_enter == NULL)
2272 goto out;
2273
2274 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2275 goto out_delete_sys_enter;
2276
2277 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2278 if (sys_exit == NULL)
2279 goto out_delete_sys_enter;
2280
2281 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2282 goto out_delete_sys_exit;
2283
2284 perf_evlist__add(evlist, sys_enter);
2285 perf_evlist__add(evlist, sys_exit);
2286
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002287 trace->syscalls.events.sys_enter = sys_enter;
2288 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002289
2290 ret = 0;
2291out:
2292 return ret;
2293
2294out_delete_sys_exit:
2295 perf_evsel__delete_priv(sys_exit);
2296out_delete_sys_enter:
2297 perf_evsel__delete_priv(sys_enter);
2298 goto out;
2299}
2300
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002301static int trace__set_ev_qualifier_filter(struct trace *trace)
2302{
2303 int err = -1;
2304 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2305 trace->ev_qualifier_ids.nr,
2306 trace->ev_qualifier_ids.entries);
2307
2308 if (filter == NULL)
2309 goto out_enomem;
2310
2311 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2312 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2313
2314 free(filter);
2315out:
2316 return err;
2317out_enomem:
2318 errno = ENOMEM;
2319 goto out;
2320}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002321
Namhyung Kimf15eb532012-10-05 14:02:16 +09002322static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002323{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002324 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002325 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002326 int err = -1, i;
2327 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002328 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002329 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002330
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002331 trace->live = true;
2332
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002333 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002334 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002335
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002336 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002337 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002338
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002339 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002340 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002341 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002342 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002343
2344 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2345 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002346 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002347
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002348 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002349 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2350 trace__sched_stat_runtime))
2351 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002352
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002353 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2354 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002355 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002356 goto out_delete_evlist;
2357 }
2358
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002359 err = trace__symbols_init(trace, evlist);
2360 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002361 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002362 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002363 }
2364
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002365 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002366
Namhyung Kimf15eb532012-10-05 14:02:16 +09002367 signal(SIGCHLD, sig_handler);
2368 signal(SIGINT, sig_handler);
2369
2370 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002371 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002372 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002373 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002374 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002375 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002376 }
2377 }
2378
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002379 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002380 if (err < 0)
2381 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002382
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002383 /*
2384 * Better not use !target__has_task() here because we need to cover the
2385 * case where no threads were specified in the command line, but a
2386 * workload was, and in that case we will fill in the thread_map when
2387 * we fork the workload in perf_evlist__prepare_workload.
2388 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002389 if (trace->filter_pids.nr > 0)
2390 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002391 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002392 err = perf_evlist__set_filter_pid(evlist, getpid());
2393
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002394 if (err < 0)
2395 goto out_error_mem;
2396
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002397 if (trace->ev_qualifier_ids.nr > 0) {
2398 err = trace__set_ev_qualifier_filter(trace);
2399 if (err < 0)
2400 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002401
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002402 pr_debug("event qualifier tracepoint filter: %s\n",
2403 trace->syscalls.events.sys_exit->filter);
2404 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002405
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002406 err = perf_evlist__apply_filters(evlist, &evsel);
2407 if (err < 0)
2408 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002409
Jiri Olsaf8850372013-11-28 17:57:22 +01002410 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002411 if (err < 0)
2412 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002413
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002414 if (!target__none(&trace->opts.target))
2415 perf_evlist__enable(evlist);
2416
Namhyung Kimf15eb532012-10-05 14:02:16 +09002417 if (forks)
2418 perf_evlist__start_workload(evlist);
2419
Jiri Olsae13798c2015-06-23 00:36:02 +02002420 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002421 evlist->threads->nr > 1 ||
2422 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002423again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002424 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002425
2426 for (i = 0; i < evlist->nr_mmaps; i++) {
2427 union perf_event *event;
2428
2429 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002430 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002431
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002432 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002433
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002434 err = perf_evlist__parse_sample(evlist, event, &sample);
2435 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002436 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002437 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002438 }
2439
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002440 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002441next_event:
2442 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002443
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002444 if (interrupted)
2445 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002446
2447 if (done && !draining) {
2448 perf_evlist__disable(evlist);
2449 draining = true;
2450 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002451 }
2452 }
2453
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002454 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002455 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002456
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002457 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2458 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2459 draining = true;
2460
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002461 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002462 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002463 } else {
2464 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002465 }
2466
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002467out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002468 thread__zput(trace->current);
2469
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002470 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002471
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002472 if (!err) {
2473 if (trace->summary)
2474 trace__fprintf_thread_summary(trace, trace->output);
2475
2476 if (trace->show_tool_stats) {
2477 fprintf(trace->output, "Stats:\n "
2478 " vfs_getname : %" PRIu64 "\n"
2479 " proc_getname: %" PRIu64 "\n",
2480 trace->stats.vfs_getname,
2481 trace->stats.proc_getname);
2482 }
2483 }
David Ahernbf2575c2013-10-08 21:26:53 -06002484
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002485out_delete_evlist:
2486 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002487 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002488 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002489 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002490{
2491 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002492
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002493out_error_sched_stat_runtime:
2494 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
2495 goto out_error;
2496
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002497out_error_raw_syscalls:
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002498 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002499 goto out_error;
2500
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002501out_error_mmap:
2502 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2503 goto out_error;
2504
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002505out_error_open:
2506 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2507
2508out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002509 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302510 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002511
2512out_error_apply_filters:
2513 fprintf(trace->output,
2514 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2515 evsel->filter, perf_evsel__name(evsel), errno,
2516 strerror_r(errno, errbuf, sizeof(errbuf)));
2517 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002518}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002519out_error_mem:
2520 fprintf(trace->output, "Not enough memory to run!\n");
2521 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002522
2523out_errno:
2524 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2525 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002526}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002527
David Ahern6810fc92013-08-28 22:29:52 -06002528static int trace__replay(struct trace *trace)
2529{
2530 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002531 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002532 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002533 struct perf_data_file file = {
2534 .path = input_name,
2535 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002536 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002537 };
David Ahern6810fc92013-08-28 22:29:52 -06002538 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002539 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002540 int err = -1;
2541
2542 trace->tool.sample = trace__process_sample;
2543 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002544 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002545 trace->tool.comm = perf_event__process_comm;
2546 trace->tool.exit = perf_event__process_exit;
2547 trace->tool.fork = perf_event__process_fork;
2548 trace->tool.attr = perf_event__process_attr;
2549 trace->tool.tracing_data = perf_event__process_tracing_data;
2550 trace->tool.build_id = perf_event__process_build_id;
2551
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002552 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002553 trace->tool.ordering_requires_timestamps = true;
2554
2555 /* add tid to output */
2556 trace->multiple_threads = true;
2557
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002558 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002559 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002560 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002561
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002562 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002563 goto out;
2564
David Ahern8fb598e2013-09-28 13:13:00 -06002565 trace->host = &session->machines.host;
2566
David Ahern6810fc92013-08-28 22:29:52 -06002567 err = perf_session__set_tracepoints_handlers(session, handlers);
2568 if (err)
2569 goto out;
2570
Namhyung Kim003824e2013-11-12 15:25:00 +09002571 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2572 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002573 /* older kernels have syscalls tp versus raw_syscalls */
2574 if (evsel == NULL)
2575 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2576 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002577
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002578 if (evsel &&
2579 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2580 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002581 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2582 goto out;
2583 }
2584
2585 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2586 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002587 if (evsel == NULL)
2588 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2589 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002590 if (evsel &&
2591 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2592 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002593 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002594 goto out;
2595 }
2596
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002597 evlist__for_each(session->evlist, evsel) {
2598 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2599 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2600 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2601 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2602 evsel->handler = trace__pgfault;
2603 }
2604
David Ahernbdc89662013-08-28 22:29:53 -06002605 err = parse_target_str(trace);
2606 if (err != 0)
2607 goto out;
2608
David Ahern6810fc92013-08-28 22:29:52 -06002609 setup_pager();
2610
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002611 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002612 if (err)
2613 pr_err("Failed to process events, error %d", err);
2614
David Ahernbf2575c2013-10-08 21:26:53 -06002615 else if (trace->summary)
2616 trace__fprintf_thread_summary(trace, trace->output);
2617
David Ahern6810fc92013-08-28 22:29:52 -06002618out:
2619 perf_session__delete(session);
2620
2621 return err;
2622}
2623
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002624static size_t trace__fprintf_threads_header(FILE *fp)
2625{
2626 size_t printed;
2627
Pekka Enberg99ff7152013-11-12 16:42:14 +02002628 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002629
2630 return printed;
2631}
2632
2633static size_t thread__dump_stats(struct thread_trace *ttrace,
2634 struct trace *trace, FILE *fp)
2635{
2636 struct stats *stats;
2637 size_t printed = 0;
2638 struct syscall *sc;
2639 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2640
2641 if (inode == NULL)
2642 return 0;
2643
2644 printed += fprintf(fp, "\n");
2645
Pekka Enberg27a778b2013-11-13 14:21:48 +02002646 printed += fprintf(fp, " syscall calls min avg max stddev\n");
2647 printed += fprintf(fp, " (msec) (msec) (msec) (%%)\n");
2648 printed += fprintf(fp, " --------------- -------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002649
David Ahernbf2575c2013-10-08 21:26:53 -06002650 /* each int_node is a syscall */
2651 while (inode) {
2652 stats = inode->priv;
2653 if (stats) {
2654 double min = (double)(stats->min) / NSEC_PER_MSEC;
2655 double max = (double)(stats->max) / NSEC_PER_MSEC;
2656 double avg = avg_stats(stats);
2657 double pct;
2658 u64 n = (u64) stats->n;
2659
2660 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2661 avg /= NSEC_PER_MSEC;
2662
2663 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002664 printed += fprintf(fp, " %-15s", sc->name);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002665 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f",
Pekka Enberg7f7a4132013-11-12 16:10:10 +02002666 n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002667 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002668 }
2669
2670 inode = intlist__next(inode);
2671 }
2672
2673 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002674
2675 return printed;
2676}
2677
David Ahern896cbb52013-09-28 13:12:59 -06002678/* struct used to pass data to per-thread function */
2679struct summary_data {
2680 FILE *fp;
2681 struct trace *trace;
2682 size_t printed;
2683};
2684
2685static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2686{
2687 struct summary_data *data = priv;
2688 FILE *fp = data->fp;
2689 size_t printed = data->printed;
2690 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002691 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002692 double ratio;
2693
2694 if (ttrace == NULL)
2695 return 0;
2696
2697 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2698
Pekka Enberg15e65c62013-11-14 18:43:30 +02002699 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002700 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002701 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002702 if (ttrace->pfmaj)
2703 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2704 if (ttrace->pfmin)
2705 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002706 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002707 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002708
2709 data->printed += printed;
2710
2711 return 0;
2712}
2713
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002714static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2715{
David Ahern896cbb52013-09-28 13:12:59 -06002716 struct summary_data data = {
2717 .fp = fp,
2718 .trace = trace
2719 };
2720 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002721
David Ahern896cbb52013-09-28 13:12:59 -06002722 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002723
David Ahern896cbb52013-09-28 13:12:59 -06002724 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002725}
2726
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002727static int trace__set_duration(const struct option *opt, const char *str,
2728 int unset __maybe_unused)
2729{
2730 struct trace *trace = opt->value;
2731
2732 trace->duration_filter = atof(str);
2733 return 0;
2734}
2735
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002736static int trace__set_filter_pids(const struct option *opt, const char *str,
2737 int unset __maybe_unused)
2738{
2739 int ret = -1;
2740 size_t i;
2741 struct trace *trace = opt->value;
2742 /*
2743 * FIXME: introduce a intarray class, plain parse csv and create a
2744 * { int nr, int entries[] } struct...
2745 */
2746 struct intlist *list = intlist__new(str);
2747
2748 if (list == NULL)
2749 return -1;
2750
2751 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2752 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2753
2754 if (trace->filter_pids.entries == NULL)
2755 goto out;
2756
2757 trace->filter_pids.entries[0] = getpid();
2758
2759 for (i = 1; i < trace->filter_pids.nr; ++i)
2760 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2761
2762 intlist__delete(list);
2763 ret = 0;
2764out:
2765 return ret;
2766}
2767
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002768static int trace__open_output(struct trace *trace, const char *filename)
2769{
2770 struct stat st;
2771
2772 if (!stat(filename, &st) && st.st_size) {
2773 char oldname[PATH_MAX];
2774
2775 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2776 unlink(oldname);
2777 rename(filename, oldname);
2778 }
2779
2780 trace->output = fopen(filename, "w");
2781
2782 return trace->output == NULL ? -errno : 0;
2783}
2784
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002785static int parse_pagefaults(const struct option *opt, const char *str,
2786 int unset __maybe_unused)
2787{
2788 int *trace_pgfaults = opt->value;
2789
2790 if (strcmp(str, "all") == 0)
2791 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2792 else if (strcmp(str, "maj") == 0)
2793 *trace_pgfaults |= TRACE_PFMAJ;
2794 else if (strcmp(str, "min") == 0)
2795 *trace_pgfaults |= TRACE_PFMIN;
2796 else
2797 return -1;
2798
2799 return 0;
2800}
2801
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002802static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2803{
2804 struct perf_evsel *evsel;
2805
2806 evlist__for_each(evlist, evsel)
2807 evsel->handler = handler;
2808}
2809
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002810int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2811{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002812 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002813 "perf trace [<options>] [<command>]",
2814 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002815 "perf trace record [<options>] [<command>]",
2816 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002817 NULL
2818 };
2819 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002820 .audit = {
2821 .machine = audit_detect_machine(),
2822 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2823 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002824 .syscalls = {
2825 . max = -1,
2826 },
2827 .opts = {
2828 .target = {
2829 .uid = UINT_MAX,
2830 .uses_mmap = true,
2831 },
2832 .user_freq = UINT_MAX,
2833 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002834 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002835 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002836 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002837 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002838 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002839 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002840 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002841 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002842 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002843 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002844 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002845 OPT_CALLBACK(0, "event", &trace.evlist, "event",
2846 "event selector. use 'perf list' to list available events",
2847 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002848 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2849 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002850 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03002851 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002852 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002853 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002854 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2855 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002856 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002857 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002858 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2859 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002860 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002861 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002862 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002863 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002864 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002865 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002866 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2867 "number of mmap data pages",
2868 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002869 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002870 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002871 OPT_CALLBACK(0, "duration", &trace, "float",
2872 "show only events with duration > N.M ms",
2873 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002874 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002875 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002876 OPT_BOOLEAN('T', "time", &trace.full_time,
2877 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002878 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2879 "Show only syscall summary with statistics"),
2880 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2881 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002882 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2883 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002884 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002885 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Kan Liang9d9cad72015-06-17 09:51:11 -04002886 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2887 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002888 OPT_END()
2889 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002890 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002891 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002892 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002893
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002894 signal(SIGSEGV, sighandler_dump_stack);
2895 signal(SIGFPE, sighandler_dump_stack);
2896
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002897 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002898
2899 if (trace.evlist == NULL) {
2900 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002901 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002902 goto out;
2903 }
2904
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002905 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2906 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002907
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002908 if (trace.trace_pgfaults) {
2909 trace.opts.sample_address = true;
2910 trace.opts.sample_time = true;
2911 }
2912
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002913 if (trace.evlist->nr_entries > 0)
2914 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2915
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002916 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2917 return trace__record(&trace, argc-1, &argv[1]);
2918
2919 /* summary_only implies summary option, but don't overwrite summary if set */
2920 if (trace.summary_only)
2921 trace.summary = trace.summary_only;
2922
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002923 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2924 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002925 pr_err("Please specify something to trace.\n");
2926 return -1;
2927 }
2928
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002929 if (output_name != NULL) {
2930 err = trace__open_output(&trace, output_name);
2931 if (err < 0) {
2932 perror("failed to create output file");
2933 goto out;
2934 }
2935 }
2936
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002937 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002938 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03002939 struct strlist_config slist_config = {
2940 .dirname = system_path(STRACE_GROUPS_DIR),
2941 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002942
2943 trace.not_ev_qualifier = *s == '!';
2944 if (trace.not_ev_qualifier)
2945 ++s;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03002946 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002947 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002948 fputs("Not enough memory to parse event qualifier",
2949 trace.output);
2950 err = -ENOMEM;
2951 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002952 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03002953
2954 err = trace__validate_ev_qualifier(&trace);
2955 if (err)
2956 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002957 }
2958
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002959 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002960 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002961 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002962 fprintf(trace.output, "%s", bf);
2963 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002964 }
2965
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002966 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002967 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002968 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002969 fprintf(trace.output, "%s", bf);
2970 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002971 }
2972
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002973 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002974 trace.opts.target.system_wide = true;
2975
David Ahern6810fc92013-08-28 22:29:52 -06002976 if (input_name)
2977 err = trace__replay(&trace);
2978 else
2979 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002980
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002981out_close:
2982 if (output_name != NULL)
2983 fclose(trace.output);
2984out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002985 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002986}