blob: 12fc6dfbae997570444e744d63be581913d45357 [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",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300602 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
603 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600604};
605static DEFINE_STRARRAY(clockid);
606
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300607static const char *socket_families[] = {
608 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
609 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
610 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
611 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
612 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
613 "ALG", "NFC", "VSOCK",
614};
615static DEFINE_STRARRAY(socket_families);
616
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300617#ifndef SOCK_TYPE_MASK
618#define SOCK_TYPE_MASK 0xf
619#endif
620
621static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
622 struct syscall_arg *arg)
623{
624 size_t printed;
625 int type = arg->val,
626 flags = type & ~SOCK_TYPE_MASK;
627
628 type &= SOCK_TYPE_MASK;
629 /*
630 * Can't use a strarray, MIPS may override for ABI reasons.
631 */
632 switch (type) {
633#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
634 P_SK_TYPE(STREAM);
635 P_SK_TYPE(DGRAM);
636 P_SK_TYPE(RAW);
637 P_SK_TYPE(RDM);
638 P_SK_TYPE(SEQPACKET);
639 P_SK_TYPE(DCCP);
640 P_SK_TYPE(PACKET);
641#undef P_SK_TYPE
642 default:
643 printed = scnprintf(bf, size, "%#x", type);
644 }
645
646#define P_SK_FLAG(n) \
647 if (flags & SOCK_##n) { \
648 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
649 flags &= ~SOCK_##n; \
650 }
651
652 P_SK_FLAG(CLOEXEC);
653 P_SK_FLAG(NONBLOCK);
654#undef P_SK_FLAG
655
656 if (flags)
657 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
658
659 return printed;
660}
661
662#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
663
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300664#ifndef MSG_PROBE
665#define MSG_PROBE 0x10
666#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600667#ifndef MSG_WAITFORONE
668#define MSG_WAITFORONE 0x10000
669#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300670#ifndef MSG_SENDPAGE_NOTLAST
671#define MSG_SENDPAGE_NOTLAST 0x20000
672#endif
673#ifndef MSG_FASTOPEN
674#define MSG_FASTOPEN 0x20000000
675#endif
676
677static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
678 struct syscall_arg *arg)
679{
680 int printed = 0, flags = arg->val;
681
682 if (flags == 0)
683 return scnprintf(bf, size, "NONE");
684#define P_MSG_FLAG(n) \
685 if (flags & MSG_##n) { \
686 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
687 flags &= ~MSG_##n; \
688 }
689
690 P_MSG_FLAG(OOB);
691 P_MSG_FLAG(PEEK);
692 P_MSG_FLAG(DONTROUTE);
693 P_MSG_FLAG(TRYHARD);
694 P_MSG_FLAG(CTRUNC);
695 P_MSG_FLAG(PROBE);
696 P_MSG_FLAG(TRUNC);
697 P_MSG_FLAG(DONTWAIT);
698 P_MSG_FLAG(EOR);
699 P_MSG_FLAG(WAITALL);
700 P_MSG_FLAG(FIN);
701 P_MSG_FLAG(SYN);
702 P_MSG_FLAG(CONFIRM);
703 P_MSG_FLAG(RST);
704 P_MSG_FLAG(ERRQUEUE);
705 P_MSG_FLAG(NOSIGNAL);
706 P_MSG_FLAG(MORE);
707 P_MSG_FLAG(WAITFORONE);
708 P_MSG_FLAG(SENDPAGE_NOTLAST);
709 P_MSG_FLAG(FASTOPEN);
710 P_MSG_FLAG(CMSG_CLOEXEC);
711#undef P_MSG_FLAG
712
713 if (flags)
714 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
715
716 return printed;
717}
718
719#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
720
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300721static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
722 struct syscall_arg *arg)
723{
724 size_t printed = 0;
725 int mode = arg->val;
726
727 if (mode == F_OK) /* 0 */
728 return scnprintf(bf, size, "F");
729#define P_MODE(n) \
730 if (mode & n##_OK) { \
731 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
732 mode &= ~n##_OK; \
733 }
734
735 P_MODE(R);
736 P_MODE(W);
737 P_MODE(X);
738#undef P_MODE
739
740 if (mode)
741 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
742
743 return printed;
744}
745
746#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
747
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300748static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
749 struct syscall_arg *arg);
750
751#define SCA_FILENAME syscall_arg__scnprintf_filename
752
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300753static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300754 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300755{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300756 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300757
758 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300759 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300760
761 if (flags == 0)
762 return scnprintf(bf, size, "RDONLY");
763#define P_FLAG(n) \
764 if (flags & O_##n) { \
765 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
766 flags &= ~O_##n; \
767 }
768
769 P_FLAG(APPEND);
770 P_FLAG(ASYNC);
771 P_FLAG(CLOEXEC);
772 P_FLAG(CREAT);
773 P_FLAG(DIRECT);
774 P_FLAG(DIRECTORY);
775 P_FLAG(EXCL);
776 P_FLAG(LARGEFILE);
777 P_FLAG(NOATIME);
778 P_FLAG(NOCTTY);
779#ifdef O_NONBLOCK
780 P_FLAG(NONBLOCK);
781#elif O_NDELAY
782 P_FLAG(NDELAY);
783#endif
784#ifdef O_PATH
785 P_FLAG(PATH);
786#endif
787 P_FLAG(RDWR);
788#ifdef O_DSYNC
789 if ((flags & O_SYNC) == O_SYNC)
790 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
791 else {
792 P_FLAG(DSYNC);
793 }
794#else
795 P_FLAG(SYNC);
796#endif
797 P_FLAG(TRUNC);
798 P_FLAG(WRONLY);
799#undef P_FLAG
800
801 if (flags)
802 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
803
804 return printed;
805}
806
807#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
808
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300809static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size,
810 struct syscall_arg *arg)
811{
812 int printed = 0, flags = arg->val;
813
814 if (flags == 0)
815 return 0;
816
817#define P_FLAG(n) \
818 if (flags & PERF_FLAG_##n) { \
819 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
820 flags &= ~PERF_FLAG_##n; \
821 }
822
823 P_FLAG(FD_NO_GROUP);
824 P_FLAG(FD_OUTPUT);
825 P_FLAG(PID_CGROUP);
826 P_FLAG(FD_CLOEXEC);
827#undef P_FLAG
828
829 if (flags)
830 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
831
832 return printed;
833}
834
835#define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags
836
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300837static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
838 struct syscall_arg *arg)
839{
840 int printed = 0, flags = arg->val;
841
842 if (flags == 0)
843 return scnprintf(bf, size, "NONE");
844#define P_FLAG(n) \
845 if (flags & EFD_##n) { \
846 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
847 flags &= ~EFD_##n; \
848 }
849
850 P_FLAG(SEMAPHORE);
851 P_FLAG(CLOEXEC);
852 P_FLAG(NONBLOCK);
853#undef P_FLAG
854
855 if (flags)
856 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
857
858 return printed;
859}
860
861#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
862
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300863static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
864 struct syscall_arg *arg)
865{
866 int printed = 0, flags = arg->val;
867
868#define P_FLAG(n) \
869 if (flags & O_##n) { \
870 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
871 flags &= ~O_##n; \
872 }
873
874 P_FLAG(CLOEXEC);
875 P_FLAG(NONBLOCK);
876#undef P_FLAG
877
878 if (flags)
879 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
880
881 return printed;
882}
883
884#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
885
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300886static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
887{
888 int sig = arg->val;
889
890 switch (sig) {
891#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
892 P_SIGNUM(HUP);
893 P_SIGNUM(INT);
894 P_SIGNUM(QUIT);
895 P_SIGNUM(ILL);
896 P_SIGNUM(TRAP);
897 P_SIGNUM(ABRT);
898 P_SIGNUM(BUS);
899 P_SIGNUM(FPE);
900 P_SIGNUM(KILL);
901 P_SIGNUM(USR1);
902 P_SIGNUM(SEGV);
903 P_SIGNUM(USR2);
904 P_SIGNUM(PIPE);
905 P_SIGNUM(ALRM);
906 P_SIGNUM(TERM);
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300907 P_SIGNUM(CHLD);
908 P_SIGNUM(CONT);
909 P_SIGNUM(STOP);
910 P_SIGNUM(TSTP);
911 P_SIGNUM(TTIN);
912 P_SIGNUM(TTOU);
913 P_SIGNUM(URG);
914 P_SIGNUM(XCPU);
915 P_SIGNUM(XFSZ);
916 P_SIGNUM(VTALRM);
917 P_SIGNUM(PROF);
918 P_SIGNUM(WINCH);
919 P_SIGNUM(IO);
920 P_SIGNUM(PWR);
921 P_SIGNUM(SYS);
Ben Hutchings02c5bb42014-02-06 01:00:41 +0000922#ifdef SIGEMT
923 P_SIGNUM(EMT);
924#endif
925#ifdef SIGSTKFLT
926 P_SIGNUM(STKFLT);
927#endif
928#ifdef SIGSWI
929 P_SIGNUM(SWI);
930#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300931 default: break;
932 }
933
934 return scnprintf(bf, size, "%#x", sig);
935}
936
937#define SCA_SIGNUM syscall_arg__scnprintf_signum
938
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300939#if defined(__i386__) || defined(__x86_64__)
940/*
941 * FIXME: Make this available to all arches.
942 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300943#define TCGETS 0x5401
944
945static const char *tioctls[] = {
946 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
947 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
948 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
949 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
950 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
951 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
952 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
953 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
954 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
955 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
956 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
957 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
958 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
959 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
960 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
961};
962
963static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300964#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300965
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300966#define STRARRAY(arg, name, array) \
967 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
968 .arg_parm = { [arg] = &strarray__##array, }
969
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300970static struct syscall_fmt {
971 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300972 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300973 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300974 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300975 bool errmsg;
976 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300977 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300978} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300979 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300980 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
981 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300982 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300983 { .name = "brk", .hexret = true,
984 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300985 { .name = "chdir", .errmsg = true,
986 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
987 { .name = "chmod", .errmsg = true,
988 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
989 { .name = "chroot", .errmsg = true,
990 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600991 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300992 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300993 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300994 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300995 { .name = "creat", .errmsg = true,
996 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300997 { .name = "dup", .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 = "dup2", .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 = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001002 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001003 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -03001004 { .name = "eventfd2", .errmsg = true,
1005 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001006 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001007 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1008 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001009 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001010 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001011 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001012 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001013 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001014 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001015 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001016 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001017 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001018 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1019 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001020 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001021 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001022 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001023 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1024 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001025 { .name = "fcntl", .errmsg = true,
1026 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1027 [1] = SCA_STRARRAY, /* cmd */ },
1028 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1029 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001030 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -03001031 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001032 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1033 [1] = SCA_FLOCK, /* cmd */ }, },
1034 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001035 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001036 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001037 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001038 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001039 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1040 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001041 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001042 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001043 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001044 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001045 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001046 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -03001047 { .name = "futex", .errmsg = true,
1048 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001049 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001050 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1051 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001052 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001053 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001054 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001055 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001056 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1057 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001058 { .name = "getxattr", .errmsg = true,
1059 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1060 { .name = "inotify_add_watch", .errmsg = true,
1061 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001062 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001063 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001064#if defined(__i386__) || defined(__x86_64__)
1065/*
1066 * FIXME: Make this available to all arches.
1067 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001068 [1] = SCA_STRHEXARRAY, /* cmd */
1069 [2] = SCA_HEX, /* arg */ },
1070 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001071#else
1072 [2] = SCA_HEX, /* arg */ }, },
1073#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001074 { .name = "kill", .errmsg = true,
1075 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001076 { .name = "lchown", .errmsg = true,
1077 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1078 { .name = "lgetxattr", .errmsg = true,
1079 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001080 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001081 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001082 { .name = "listxattr", .errmsg = true,
1083 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001084 { .name = "llistxattr", .errmsg = true,
1085 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1086 { .name = "lremovexattr", .errmsg = true,
1087 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001088 { .name = "lseek", .errmsg = true,
1089 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1090 [2] = SCA_STRARRAY, /* whence */ },
1091 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001092 { .name = "lsetxattr", .errmsg = true,
1093 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001094 { .name = "lstat", .errmsg = true, .alias = "newlstat",
1095 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001096 { .name = "lsxattr", .errmsg = true,
1097 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001098 { .name = "madvise", .errmsg = true,
1099 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1100 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001101 { .name = "mkdir", .errmsg = true,
1102 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001103 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001104 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1105 [1] = SCA_FILENAME, /* pathname */ }, },
1106 { .name = "mknod", .errmsg = true,
1107 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001108 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001109 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1110 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001111 { .name = "mlock", .errmsg = true,
1112 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1113 { .name = "mlockall", .errmsg = true,
1114 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001115 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001116 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001117 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001118 [3] = SCA_MMAP_FLAGS, /* flags */
1119 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001120 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001121 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1122 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001123 { .name = "mq_unlink", .errmsg = true,
1124 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001125 { .name = "mremap", .hexret = true,
1126 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001127 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001128 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001129 { .name = "munlock", .errmsg = true,
1130 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001131 { .name = "munmap", .errmsg = true,
1132 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001133 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001134 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001135 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001136 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1137 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001138 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001139 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1140 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001141 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001142 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1143 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001144 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001145 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001146 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001147 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001148 { .name = "perf_event_open", .errmsg = true,
1149 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1150 [2] = SCA_INT, /* cpu */
1151 [3] = SCA_FD, /* group_fd */
1152 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001153 { .name = "pipe2", .errmsg = true,
1154 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001155 { .name = "poll", .errmsg = true, .timeout = true, },
1156 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001157 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001158 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001159 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001160 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001161 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001162 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001163 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001164 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001165 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001166 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001167 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001168 { .name = "readlink", .errmsg = true,
1169 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001170 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001171 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1172 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001173 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001174 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001175 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001176 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1177 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001178 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001179 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1180 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001181 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001182 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1183 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001184 { .name = "removexattr", .errmsg = true,
1185 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001186 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001187 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001188 { .name = "rmdir", .errmsg = true,
1189 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001190 { .name = "rt_sigaction", .errmsg = true,
1191 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001192 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001193 { .name = "rt_sigqueueinfo", .errmsg = true,
1194 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1195 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1196 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001197 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001198 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001199 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1200 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001201 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001202 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1203 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001204 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001205 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1206 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001207 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1208 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001209 { .name = "setxattr", .errmsg = true,
1210 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001211 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001212 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001213 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001214 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1215 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001216 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001217 { .name = "socketpair", .errmsg = true,
1218 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1219 [1] = SCA_SK_TYPE, /* type */ },
1220 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001221 { .name = "stat", .errmsg = true, .alias = "newstat",
1222 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001223 { .name = "statfs", .errmsg = true,
1224 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1225 { .name = "swapoff", .errmsg = true,
1226 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1227 { .name = "swapon", .errmsg = true,
1228 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001229 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001230 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001231 { .name = "tgkill", .errmsg = true,
1232 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1233 { .name = "tkill", .errmsg = true,
1234 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001235 { .name = "truncate", .errmsg = true,
1236 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001237 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001238 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001239 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1240 [1] = SCA_FILENAME, /* pathname */ }, },
1241 { .name = "utime", .errmsg = true,
1242 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001243 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001244 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1245 [1] = SCA_FILENAME, /* filename */ }, },
1246 { .name = "utimes", .errmsg = true,
1247 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001248 { .name = "vmsplice", .errmsg = true,
1249 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001250 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001251 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001252 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001253 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001254};
1255
1256static int syscall_fmt__cmp(const void *name, const void *fmtp)
1257{
1258 const struct syscall_fmt *fmt = fmtp;
1259 return strcmp(name, fmt->name);
1260}
1261
1262static struct syscall_fmt *syscall_fmt__find(const char *name)
1263{
1264 const int nmemb = ARRAY_SIZE(syscall_fmts);
1265 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1266}
1267
1268struct syscall {
1269 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001270 int nr_args;
1271 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001272 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001273 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001274 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001275 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001276 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001277};
1278
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001279static size_t fprintf_duration(unsigned long t, FILE *fp)
1280{
1281 double duration = (double)t / NSEC_PER_MSEC;
1282 size_t printed = fprintf(fp, "(");
1283
1284 if (duration >= 1.0)
1285 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1286 else if (duration >= 0.01)
1287 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1288 else
1289 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001290 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001291}
1292
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001293/**
1294 * filename.ptr: The filename char pointer that will be vfs_getname'd
1295 * filename.entry_str_pos: Where to insert the string translated from
1296 * filename.ptr by the vfs_getname tracepoint/kprobe.
1297 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001298struct thread_trace {
1299 u64 entry_time;
1300 u64 exit_time;
1301 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001302 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001303 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001304 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001305 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001306 struct {
1307 unsigned long ptr;
1308 int entry_str_pos;
1309 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001310 struct {
1311 int max;
1312 char **table;
1313 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001314
1315 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001316};
1317
1318static struct thread_trace *thread_trace__new(void)
1319{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001320 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1321
1322 if (ttrace)
1323 ttrace->paths.max = -1;
1324
David Ahernbf2575c2013-10-08 21:26:53 -06001325 ttrace->syscall_stats = intlist__new(NULL);
1326
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001327 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001328}
1329
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001330static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001331{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001332 struct thread_trace *ttrace;
1333
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001334 if (thread == NULL)
1335 goto fail;
1336
Namhyung Kim89dceb22014-10-06 09:46:03 +09001337 if (thread__priv(thread) == NULL)
1338 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001339
Namhyung Kim89dceb22014-10-06 09:46:03 +09001340 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001341 goto fail;
1342
Namhyung Kim89dceb22014-10-06 09:46:03 +09001343 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001344 ++ttrace->nr_events;
1345
1346 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001347fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001348 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001349 "WARNING: not enough memory, dropping samples!\n");
1350 return NULL;
1351}
1352
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001353#define TRACE_PFMAJ (1 << 0)
1354#define TRACE_PFMIN (1 << 1)
1355
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001356static const size_t trace__entry_str_size = 2048;
1357
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001358struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001359 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001360 struct {
1361 int machine;
1362 int open_id;
1363 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001364 struct {
1365 int max;
1366 struct syscall *table;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001367 struct {
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001368 struct perf_evsel *sys_enter,
1369 *sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001370 } events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001371 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001372 struct record_opts opts;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001373 struct perf_evlist *evlist;
David Ahern8fb598e2013-09-28 13:13:00 -06001374 struct machine *host;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001375 struct thread *current;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001376 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001377 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001378 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001379 struct strlist *ev_qualifier;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001380 struct {
1381 size_t nr;
1382 int *entries;
1383 } ev_qualifier_ids;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001384 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -06001385 struct intlist *tid_list;
1386 struct intlist *pid_list;
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08001387 struct {
1388 size_t nr;
1389 pid_t *entries;
1390 } filter_pids;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001391 double duration_filter;
1392 double runtime_ms;
1393 struct {
1394 u64 vfs_getname,
1395 proc_getname;
1396 } stats;
1397 bool not_ev_qualifier;
1398 bool live;
1399 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001400 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001401 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001402 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001403 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001404 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001405 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001406 bool trace_syscalls;
Yunlong Songe366a6d2015-04-02 21:47:18 +08001407 bool force;
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03001408 bool vfs_getname;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001409 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001410};
1411
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001412static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001413{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001414 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001415
1416 if (fd > ttrace->paths.max) {
1417 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1418
1419 if (npath == NULL)
1420 return -1;
1421
1422 if (ttrace->paths.max != -1) {
1423 memset(npath + ttrace->paths.max + 1, 0,
1424 (fd - ttrace->paths.max) * sizeof(char *));
1425 } else {
1426 memset(npath, 0, (fd + 1) * sizeof(char *));
1427 }
1428
1429 ttrace->paths.table = npath;
1430 ttrace->paths.max = fd;
1431 }
1432
1433 ttrace->paths.table[fd] = strdup(pathname);
1434
1435 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1436}
1437
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001438static int thread__read_fd_path(struct thread *thread, int fd)
1439{
1440 char linkname[PATH_MAX], pathname[PATH_MAX];
1441 struct stat st;
1442 int ret;
1443
1444 if (thread->pid_ == thread->tid) {
1445 scnprintf(linkname, sizeof(linkname),
1446 "/proc/%d/fd/%d", thread->pid_, fd);
1447 } else {
1448 scnprintf(linkname, sizeof(linkname),
1449 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1450 }
1451
1452 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1453 return -1;
1454
1455 ret = readlink(linkname, pathname, sizeof(pathname));
1456
1457 if (ret < 0 || ret > st.st_size)
1458 return -1;
1459
1460 pathname[ret] = '\0';
1461 return trace__set_fd_pathname(thread, fd, pathname);
1462}
1463
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001464static const char *thread__fd_path(struct thread *thread, int fd,
1465 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001466{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001467 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001468
1469 if (ttrace == NULL)
1470 return NULL;
1471
1472 if (fd < 0)
1473 return NULL;
1474
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001475 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001476 if (!trace->live)
1477 return NULL;
1478 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001479 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001480 return NULL;
1481 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001482
1483 return ttrace->paths.table[fd];
1484}
1485
1486static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1487 struct syscall_arg *arg)
1488{
1489 int fd = arg->val;
1490 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001491 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001492
1493 if (path)
1494 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1495
1496 return printed;
1497}
1498
1499static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1500 struct syscall_arg *arg)
1501{
1502 int fd = arg->val;
1503 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001504 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001505
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001506 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1507 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001508
1509 return printed;
1510}
1511
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001512static void thread__set_filename_pos(struct thread *thread, const char *bf,
1513 unsigned long ptr)
1514{
1515 struct thread_trace *ttrace = thread__priv(thread);
1516
1517 ttrace->filename.ptr = ptr;
1518 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1519}
1520
1521static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1522 struct syscall_arg *arg)
1523{
1524 unsigned long ptr = arg->val;
1525
1526 if (!arg->trace->vfs_getname)
1527 return scnprintf(bf, size, "%#x", ptr);
1528
1529 thread__set_filename_pos(arg->thread, bf, ptr);
1530 return 0;
1531}
1532
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001533static bool trace__filter_duration(struct trace *trace, double t)
1534{
1535 return t < (trace->duration_filter * NSEC_PER_MSEC);
1536}
1537
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001538static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1539{
1540 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1541
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001542 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001543}
1544
Namhyung Kimf15eb532012-10-05 14:02:16 +09001545static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001546static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001547
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001548static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001549{
1550 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001551 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001552}
1553
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001554static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001555 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001556{
1557 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001558 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001559
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001560 if (trace->multiple_threads) {
1561 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001562 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001563 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001564 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001565
1566 return printed;
1567}
1568
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001569static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001570 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001571{
1572 int ret = 0;
1573
1574 switch (event->header.type) {
1575 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001576 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001577 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001578 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001579 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001580 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001581 break;
1582 }
1583
1584 return ret;
1585}
1586
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001587static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001588 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001589 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001590 struct machine *machine)
1591{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001592 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001593 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001594}
1595
1596static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1597{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001598 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001599
1600 if (err)
1601 return err;
1602
David Ahern8fb598e2013-09-28 13:13:00 -06001603 trace->host = machine__new_host();
1604 if (trace->host == NULL)
1605 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001606
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001607 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001608 return -errno;
1609
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001610 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001611 evlist->threads, trace__tool_process, false,
1612 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001613 if (err)
1614 symbol__exit();
1615
1616 return err;
1617}
1618
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001619static int syscall__set_arg_fmts(struct syscall *sc)
1620{
1621 struct format_field *field;
1622 int idx = 0;
1623
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001624 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001625 if (sc->arg_scnprintf == NULL)
1626 return -1;
1627
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001628 if (sc->fmt)
1629 sc->arg_parm = sc->fmt->arg_parm;
1630
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001631 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001632 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1633 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1634 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001635 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1636 ++idx;
1637 }
1638
1639 return 0;
1640}
1641
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001642static int trace__read_syscall_info(struct trace *trace, int id)
1643{
1644 char tp_name[128];
1645 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001646 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001647
1648 if (name == NULL)
1649 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001650
1651 if (id > trace->syscalls.max) {
1652 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1653
1654 if (nsyscalls == NULL)
1655 return -1;
1656
1657 if (trace->syscalls.max != -1) {
1658 memset(nsyscalls + trace->syscalls.max + 1, 0,
1659 (id - trace->syscalls.max) * sizeof(*sc));
1660 } else {
1661 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1662 }
1663
1664 trace->syscalls.table = nsyscalls;
1665 trace->syscalls.max = id;
1666 }
1667
1668 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001669 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001670
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001671 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001672
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001673 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001674 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001675
1676 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1677 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001678 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001679 }
1680
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001681 if (sc->tp_format == NULL)
1682 return -1;
1683
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001684 sc->args = sc->tp_format->format.fields;
1685 sc->nr_args = sc->tp_format->format.nr_fields;
1686 /* drop nr field - not relevant here; does not exist on older kernels */
1687 if (sc->args && strcmp(sc->args->name, "nr") == 0) {
1688 sc->args = sc->args->next;
1689 --sc->nr_args;
1690 }
1691
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001692 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1693
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001694 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001695}
1696
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001697static int trace__validate_ev_qualifier(struct trace *trace)
1698{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001699 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001700 struct str_node *pos;
1701
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001702 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1703 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1704 sizeof(trace->ev_qualifier_ids.entries[0]));
1705
1706 if (trace->ev_qualifier_ids.entries == NULL) {
1707 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1708 trace->output);
1709 err = -EINVAL;
1710 goto out;
1711 }
1712
1713 i = 0;
1714
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001715 strlist__for_each(pos, trace->ev_qualifier) {
1716 const char *sc = pos->s;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001717 int id = audit_name_to_syscall(sc, trace->audit.machine);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001718
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001719 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001720 if (err == 0) {
1721 fputs("Error:\tInvalid syscall ", trace->output);
1722 err = -EINVAL;
1723 } else {
1724 fputs(", ", trace->output);
1725 }
1726
1727 fputs(sc, trace->output);
1728 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001729
1730 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001731 }
1732
1733 if (err < 0) {
1734 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1735 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001736 zfree(&trace->ev_qualifier_ids.entries);
1737 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001738 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001739out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001740 return err;
1741}
1742
David Ahern55d43bc2015-02-19 15:00:22 -05001743/*
1744 * args is to be interpreted as a series of longs but we need to handle
1745 * 8-byte unaligned accesses. args points to raw_data within the event
1746 * and raw_data is guaranteed to be 8-byte unaligned because it is
1747 * preceded by raw_size which is a u32. So we need to copy args to a temp
1748 * variable to read it. Most notably this avoids extended load instructions
1749 * on unaligned addresses
1750 */
1751
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001752static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001753 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001754 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001755{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001756 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001757 unsigned char *p;
1758 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001759
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001760 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001761 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001762 u8 bit = 1;
1763 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001764 .idx = 0,
1765 .mask = 0,
1766 .trace = trace,
1767 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001768 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001769
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001770 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001771 field = field->next, ++arg.idx, bit <<= 1) {
1772 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001773 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001774
1775 /* special care for unaligned accesses */
1776 p = args + sizeof(unsigned long) * arg.idx;
1777 memcpy(&val, p, sizeof(val));
1778
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001779 /*
1780 * Suppress this argument if its value is zero and
1781 * and we don't have a string associated in an
1782 * strarray for it.
1783 */
David Ahern55d43bc2015-02-19 15:00:22 -05001784 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001785 !(sc->arg_scnprintf &&
1786 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1787 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001788 continue;
1789
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001790 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001791 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001792 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001793 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001794 if (sc->arg_parm)
1795 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001796 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1797 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001798 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001799 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001800 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001801 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001802 }
1803 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001804 int i = 0;
1805
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001806 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001807 /* special care for unaligned accesses */
1808 p = args + sizeof(unsigned long) * i;
1809 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001810 printed += scnprintf(bf + printed, size - printed,
1811 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001812 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001813 ++i;
1814 }
1815 }
1816
1817 return printed;
1818}
1819
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001820typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001821 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001822 struct perf_sample *sample);
1823
1824static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001825 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001826{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001827
1828 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001829
1830 /*
1831 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1832 * before that, leaving at a higher verbosity level till that is
1833 * explained. Reproduced with plain ftrace with:
1834 *
1835 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1836 * grep "NR -1 " /t/trace_pipe
1837 *
1838 * After generating some load on the machine.
1839 */
1840 if (verbose > 1) {
1841 static u64 n;
1842 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1843 id, perf_evsel__name(evsel), ++n);
1844 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001845 return NULL;
1846 }
1847
1848 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1849 trace__read_syscall_info(trace, id))
1850 goto out_cant_read;
1851
1852 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1853 goto out_cant_read;
1854
1855 return &trace->syscalls.table[id];
1856
1857out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001858 if (verbose) {
1859 fprintf(trace->output, "Problems reading syscall %d", id);
1860 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1861 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1862 fputs(" information\n", trace->output);
1863 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001864 return NULL;
1865}
1866
David Ahernbf2575c2013-10-08 21:26:53 -06001867static void thread__update_stats(struct thread_trace *ttrace,
1868 int id, struct perf_sample *sample)
1869{
1870 struct int_node *inode;
1871 struct stats *stats;
1872 u64 duration = 0;
1873
1874 inode = intlist__findnew(ttrace->syscall_stats, id);
1875 if (inode == NULL)
1876 return;
1877
1878 stats = inode->priv;
1879 if (stats == NULL) {
1880 stats = malloc(sizeof(struct stats));
1881 if (stats == NULL)
1882 return;
1883 init_stats(stats);
1884 inode->priv = stats;
1885 }
1886
1887 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1888 duration = sample->time - ttrace->entry_time;
1889
1890 update_stats(stats, duration);
1891}
1892
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001893static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1894{
1895 struct thread_trace *ttrace;
1896 u64 duration;
1897 size_t printed;
1898
1899 if (trace->current == NULL)
1900 return 0;
1901
1902 ttrace = thread__priv(trace->current);
1903
1904 if (!ttrace->entry_pending)
1905 return 0;
1906
1907 duration = sample->time - ttrace->entry_time;
1908
1909 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1910 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1911 ttrace->entry_pending = false;
1912
1913 return printed;
1914}
1915
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001916static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001917 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001918 struct perf_sample *sample)
1919{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001920 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001921 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001922 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001923 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001924 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001925 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001926 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001927
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001928 if (sc == NULL)
1929 return -1;
1930
David Ahern8fb598e2013-09-28 13:13:00 -06001931 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001932 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001933 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001934 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001935
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001936 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001937
1938 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001939 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001940 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001941 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001942 }
1943
David Ahern13f22a22015-03-19 12:23:03 -06001944 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001945 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001946
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001947 ttrace->entry_time = sample->time;
1948 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001949 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001950
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001951 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001952 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001953
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001954 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001955 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001956 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1957 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001958 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001959 } else
1960 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001961
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001962 if (trace->current != thread) {
1963 thread__put(trace->current);
1964 trace->current = thread__get(thread);
1965 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001966 err = 0;
1967out_put:
1968 thread__put(thread);
1969 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001970}
1971
1972static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001973 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001974 struct perf_sample *sample)
1975{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001976 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001977 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001978 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001979 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001980 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001981 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001982
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001983 if (sc == NULL)
1984 return -1;
1985
David Ahern8fb598e2013-09-28 13:13:00 -06001986 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001987 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001988 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001989 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001990
David Ahernbf2575c2013-10-08 21:26:53 -06001991 if (trace->summary)
1992 thread__update_stats(ttrace, id, sample);
1993
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001994 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001995
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001996 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1997 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1998 trace->last_vfs_getname = NULL;
1999 ++trace->stats.vfs_getname;
2000 }
2001
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002002 ttrace->exit_time = sample->time;
2003
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002004 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002005 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002006 if (trace__filter_duration(trace, duration))
2007 goto out;
2008 } else if (trace->duration_filter)
2009 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002010
David Ahernfd2eaba2013-11-12 09:31:15 -07002011 if (trace->summary_only)
2012 goto out;
2013
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002014 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002015
2016 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002017 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002018 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002019 fprintf(trace->output, " ... [");
2020 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
2021 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002022 }
2023
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002024 if (sc->fmt == NULL) {
2025signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002026 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002027 } else if (ret < 0 && sc->fmt->errmsg) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00002028 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002029 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
2030 *e = audit_errno_to_name(-ret);
2031
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002032 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002033 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002034 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03002035 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002036 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002037 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002038 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002039
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002040 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002041out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002042 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002043 err = 0;
2044out_put:
2045 thread__put(thread);
2046 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002047}
2048
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002049static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002050 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002051 struct perf_sample *sample)
2052{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002053 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2054 struct thread_trace *ttrace;
2055 size_t filename_len, entry_str_len, to_move;
2056 ssize_t remaining_space;
2057 char *pos;
2058 const char *filename;
2059
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002060 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002061
2062 if (!thread)
2063 goto out;
2064
2065 ttrace = thread__priv(thread);
2066 if (!ttrace)
2067 goto out;
2068
2069 if (!ttrace->filename.ptr)
2070 goto out;
2071
2072 entry_str_len = strlen(ttrace->entry_str);
2073 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2074 if (remaining_space <= 0)
2075 goto out;
2076
2077 filename = trace->last_vfs_getname;
2078 filename_len = strlen(filename);
2079 if (filename_len > (size_t)remaining_space) {
2080 filename += filename_len - remaining_space;
2081 filename_len = remaining_space;
2082 }
2083
2084 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2085 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2086 memmove(pos + filename_len, pos, to_move);
2087 memcpy(pos, filename, filename_len);
2088
2089 ttrace->filename.ptr = 0;
2090 ttrace->filename.entry_str_pos = 0;
2091out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002092 return 0;
2093}
2094
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002095static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002096 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002097 struct perf_sample *sample)
2098{
2099 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2100 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06002101 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03002102 sample->pid,
2103 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002104 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002105
2106 if (ttrace == NULL)
2107 goto out_dump;
2108
2109 ttrace->runtime_ms += runtime_ms;
2110 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002111 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002112 return 0;
2113
2114out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002115 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002116 evsel->name,
2117 perf_evsel__strval(evsel, sample, "comm"),
2118 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2119 runtime,
2120 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002121 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002122 return 0;
2123}
2124
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002125static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2126 union perf_event *event __maybe_unused,
2127 struct perf_sample *sample)
2128{
2129 trace__printf_interrupted_entry(trace, sample);
2130 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002131
2132 if (trace->trace_syscalls)
2133 fprintf(trace->output, "( ): ");
2134
2135 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002136
2137 if (evsel->tp_format) {
2138 event_format__fprintf(evsel->tp_format, sample->cpu,
2139 sample->raw_data, sample->raw_size,
2140 trace->output);
2141 }
2142
2143 fprintf(trace->output, ")\n");
2144 return 0;
2145}
2146
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002147static void print_location(FILE *f, struct perf_sample *sample,
2148 struct addr_location *al,
2149 bool print_dso, bool print_sym)
2150{
2151
2152 if ((verbose || print_dso) && al->map)
2153 fprintf(f, "%s@", al->map->dso->long_name);
2154
2155 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002156 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002157 al->addr - al->sym->start);
2158 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002159 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002160 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002161 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002162}
2163
2164static int trace__pgfault(struct trace *trace,
2165 struct perf_evsel *evsel,
2166 union perf_event *event,
2167 struct perf_sample *sample)
2168{
2169 struct thread *thread;
2170 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
2171 struct addr_location al;
2172 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002173 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002174 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002175
2176 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002177 ttrace = thread__trace(thread, trace->output);
2178 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002179 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002180
2181 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2182 ttrace->pfmaj++;
2183 else
2184 ttrace->pfmin++;
2185
2186 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002187 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002188
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002189 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002190 sample->ip, &al);
2191
2192 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2193
2194 fprintf(trace->output, "%sfault [",
2195 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2196 "maj" : "min");
2197
2198 print_location(trace->output, sample, &al, false, true);
2199
2200 fprintf(trace->output, "] => ");
2201
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002202 thread__find_addr_location(thread, cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002203 sample->addr, &al);
2204
2205 if (!al.map) {
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002206 thread__find_addr_location(thread, cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002207 MAP__FUNCTION, sample->addr, &al);
2208
2209 if (al.map)
2210 map_type = 'x';
2211 else
2212 map_type = '?';
2213 }
2214
2215 print_location(trace->output, sample, &al, true, false);
2216
2217 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002218out:
2219 err = 0;
2220out_put:
2221 thread__put(thread);
2222 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002223}
2224
David Ahernbdc89662013-08-28 22:29:53 -06002225static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2226{
2227 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2228 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2229 return false;
2230
2231 if (trace->pid_list || trace->tid_list)
2232 return true;
2233
2234 return false;
2235}
2236
David Ahern6810fc92013-08-28 22:29:52 -06002237static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002238 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002239 struct perf_sample *sample,
2240 struct perf_evsel *evsel,
2241 struct machine *machine __maybe_unused)
2242{
2243 struct trace *trace = container_of(tool, struct trace, tool);
2244 int err = 0;
2245
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002246 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002247
David Ahernbdc89662013-08-28 22:29:53 -06002248 if (skip_sample(trace, sample))
2249 return 0;
2250
David Ahern4bb09192013-09-04 12:37:43 -06002251 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06002252 trace->base_time = sample->time;
2253
David Ahern31605652013-12-04 19:41:41 -07002254 if (handler) {
2255 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002256 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002257 }
David Ahern6810fc92013-08-28 22:29:52 -06002258
2259 return err;
2260}
2261
David Ahernbdc89662013-08-28 22:29:53 -06002262static int parse_target_str(struct trace *trace)
2263{
2264 if (trace->opts.target.pid) {
2265 trace->pid_list = intlist__new(trace->opts.target.pid);
2266 if (trace->pid_list == NULL) {
2267 pr_err("Error parsing process id string\n");
2268 return -EINVAL;
2269 }
2270 }
2271
2272 if (trace->opts.target.tid) {
2273 trace->tid_list = intlist__new(trace->opts.target.tid);
2274 if (trace->tid_list == NULL) {
2275 pr_err("Error parsing thread id string\n");
2276 return -EINVAL;
2277 }
2278 }
2279
2280 return 0;
2281}
2282
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002283static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002284{
2285 unsigned int rec_argc, i, j;
2286 const char **rec_argv;
2287 const char * const record_args[] = {
2288 "record",
2289 "-R",
2290 "-m", "1024",
2291 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002292 };
2293
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002294 const char * const sc_args[] = { "-e", };
2295 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2296 const char * const majpf_args[] = { "-e", "major-faults" };
2297 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2298 const char * const minpf_args[] = { "-e", "minor-faults" };
2299 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2300
David Ahern9aca7f12013-12-04 19:41:39 -07002301 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002302 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2303 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002304 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2305
2306 if (rec_argv == NULL)
2307 return -ENOMEM;
2308
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002309 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002310 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002311 rec_argv[j++] = record_args[i];
2312
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002313 if (trace->trace_syscalls) {
2314 for (i = 0; i < sc_args_nr; i++)
2315 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002316
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002317 /* event string may be different for older kernels - e.g., RHEL6 */
2318 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2319 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2320 else if (is_valid_tracepoint("syscalls:sys_enter"))
2321 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2322 else {
2323 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2324 return -1;
2325 }
David Ahern9aca7f12013-12-04 19:41:39 -07002326 }
David Ahern9aca7f12013-12-04 19:41:39 -07002327
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002328 if (trace->trace_pgfaults & TRACE_PFMAJ)
2329 for (i = 0; i < majpf_args_nr; i++)
2330 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002331
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002332 if (trace->trace_pgfaults & TRACE_PFMIN)
2333 for (i = 0; i < minpf_args_nr; i++)
2334 rec_argv[j++] = minpf_args[i];
2335
2336 for (i = 0; i < (unsigned int)argc; i++)
2337 rec_argv[j++] = argv[i];
2338
2339 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002340}
2341
David Ahernbf2575c2013-10-08 21:26:53 -06002342static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2343
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002344static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002345{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002346 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002347 if (evsel == NULL)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002348 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002349
2350 if (perf_evsel__field(evsel, "pathname") == NULL) {
2351 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002352 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002353 }
2354
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002355 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002356 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002357 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002358}
2359
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002360static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2361 u64 config)
2362{
2363 struct perf_evsel *evsel;
2364 struct perf_event_attr attr = {
2365 .type = PERF_TYPE_SOFTWARE,
2366 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002367 };
2368
2369 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002370 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002371
2372 event_attr_init(&attr);
2373
2374 evsel = perf_evsel__new(&attr);
2375 if (!evsel)
2376 return -ENOMEM;
2377
2378 evsel->handler = trace__pgfault;
2379 perf_evlist__add(evlist, evsel);
2380
2381 return 0;
2382}
2383
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002384static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2385{
2386 const u32 type = event->header.type;
2387 struct perf_evsel *evsel;
2388
2389 if (!trace->full_time && trace->base_time == 0)
2390 trace->base_time = sample->time;
2391
2392 if (type != PERF_RECORD_SAMPLE) {
2393 trace__process_event(trace, trace->host, event, sample);
2394 return;
2395 }
2396
2397 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2398 if (evsel == NULL) {
2399 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2400 return;
2401 }
2402
2403 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2404 sample->raw_data == NULL) {
2405 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2406 perf_evsel__name(evsel), sample->tid,
2407 sample->cpu, sample->raw_size);
2408 } else {
2409 tracepoint_handler handler = evsel->handler;
2410 handler(trace, evsel, event, sample);
2411 }
2412}
2413
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002414static int trace__add_syscall_newtp(struct trace *trace)
2415{
2416 int ret = -1;
2417 struct perf_evlist *evlist = trace->evlist;
2418 struct perf_evsel *sys_enter, *sys_exit;
2419
2420 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2421 if (sys_enter == NULL)
2422 goto out;
2423
2424 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2425 goto out_delete_sys_enter;
2426
2427 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2428 if (sys_exit == NULL)
2429 goto out_delete_sys_enter;
2430
2431 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2432 goto out_delete_sys_exit;
2433
2434 perf_evlist__add(evlist, sys_enter);
2435 perf_evlist__add(evlist, sys_exit);
2436
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002437 trace->syscalls.events.sys_enter = sys_enter;
2438 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002439
2440 ret = 0;
2441out:
2442 return ret;
2443
2444out_delete_sys_exit:
2445 perf_evsel__delete_priv(sys_exit);
2446out_delete_sys_enter:
2447 perf_evsel__delete_priv(sys_enter);
2448 goto out;
2449}
2450
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002451static int trace__set_ev_qualifier_filter(struct trace *trace)
2452{
2453 int err = -1;
2454 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2455 trace->ev_qualifier_ids.nr,
2456 trace->ev_qualifier_ids.entries);
2457
2458 if (filter == NULL)
2459 goto out_enomem;
2460
2461 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2462 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2463
2464 free(filter);
2465out:
2466 return err;
2467out_enomem:
2468 errno = ENOMEM;
2469 goto out;
2470}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002471
Namhyung Kimf15eb532012-10-05 14:02:16 +09002472static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002473{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002474 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002475 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002476 int err = -1, i;
2477 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002478 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002479 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002480
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002481 trace->live = true;
2482
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002483 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002484 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002485
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002486 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002487 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002488
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002489 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002490 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002491 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002492 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002493
2494 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2495 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002496 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002497
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002498 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002499 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2500 trace__sched_stat_runtime))
2501 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002502
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002503 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2504 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002505 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002506 goto out_delete_evlist;
2507 }
2508
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002509 err = trace__symbols_init(trace, evlist);
2510 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002511 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002512 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002513 }
2514
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002515 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002516
Namhyung Kimf15eb532012-10-05 14:02:16 +09002517 signal(SIGCHLD, sig_handler);
2518 signal(SIGINT, sig_handler);
2519
2520 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002521 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002522 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002523 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002524 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002525 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002526 }
2527 }
2528
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002529 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002530 if (err < 0)
2531 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002532
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002533 /*
2534 * Better not use !target__has_task() here because we need to cover the
2535 * case where no threads were specified in the command line, but a
2536 * workload was, and in that case we will fill in the thread_map when
2537 * we fork the workload in perf_evlist__prepare_workload.
2538 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002539 if (trace->filter_pids.nr > 0)
2540 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002541 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002542 err = perf_evlist__set_filter_pid(evlist, getpid());
2543
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002544 if (err < 0)
2545 goto out_error_mem;
2546
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002547 if (trace->ev_qualifier_ids.nr > 0) {
2548 err = trace__set_ev_qualifier_filter(trace);
2549 if (err < 0)
2550 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002551
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002552 pr_debug("event qualifier tracepoint filter: %s\n",
2553 trace->syscalls.events.sys_exit->filter);
2554 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002555
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002556 err = perf_evlist__apply_filters(evlist, &evsel);
2557 if (err < 0)
2558 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002559
Jiri Olsaf8850372013-11-28 17:57:22 +01002560 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002561 if (err < 0)
2562 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002563
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002564 if (!target__none(&trace->opts.target))
2565 perf_evlist__enable(evlist);
2566
Namhyung Kimf15eb532012-10-05 14:02:16 +09002567 if (forks)
2568 perf_evlist__start_workload(evlist);
2569
Jiri Olsae13798c2015-06-23 00:36:02 +02002570 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002571 evlist->threads->nr > 1 ||
2572 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002573again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002574 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002575
2576 for (i = 0; i < evlist->nr_mmaps; i++) {
2577 union perf_event *event;
2578
2579 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002580 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002581
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002582 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002583
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002584 err = perf_evlist__parse_sample(evlist, event, &sample);
2585 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002586 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002587 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002588 }
2589
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002590 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002591next_event:
2592 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002593
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002594 if (interrupted)
2595 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002596
2597 if (done && !draining) {
2598 perf_evlist__disable(evlist);
2599 draining = true;
2600 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002601 }
2602 }
2603
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002604 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002605 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002606
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002607 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2608 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2609 draining = true;
2610
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002611 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002612 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002613 } else {
2614 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002615 }
2616
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002617out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002618 thread__zput(trace->current);
2619
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002620 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002621
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002622 if (!err) {
2623 if (trace->summary)
2624 trace__fprintf_thread_summary(trace, trace->output);
2625
2626 if (trace->show_tool_stats) {
2627 fprintf(trace->output, "Stats:\n "
2628 " vfs_getname : %" PRIu64 "\n"
2629 " proc_getname: %" PRIu64 "\n",
2630 trace->stats.vfs_getname,
2631 trace->stats.proc_getname);
2632 }
2633 }
David Ahernbf2575c2013-10-08 21:26:53 -06002634
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002635out_delete_evlist:
2636 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002637 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002638 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002639 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002640{
2641 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002642
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002643out_error_sched_stat_runtime:
2644 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
2645 goto out_error;
2646
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002647out_error_raw_syscalls:
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002648 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002649 goto out_error;
2650
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002651out_error_mmap:
2652 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2653 goto out_error;
2654
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002655out_error_open:
2656 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2657
2658out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002659 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302660 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002661
2662out_error_apply_filters:
2663 fprintf(trace->output,
2664 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2665 evsel->filter, perf_evsel__name(evsel), errno,
2666 strerror_r(errno, errbuf, sizeof(errbuf)));
2667 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002668}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002669out_error_mem:
2670 fprintf(trace->output, "Not enough memory to run!\n");
2671 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002672
2673out_errno:
2674 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2675 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002676}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002677
David Ahern6810fc92013-08-28 22:29:52 -06002678static int trace__replay(struct trace *trace)
2679{
2680 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002681 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002682 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002683 struct perf_data_file file = {
2684 .path = input_name,
2685 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002686 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002687 };
David Ahern6810fc92013-08-28 22:29:52 -06002688 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002689 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002690 int err = -1;
2691
2692 trace->tool.sample = trace__process_sample;
2693 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002694 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002695 trace->tool.comm = perf_event__process_comm;
2696 trace->tool.exit = perf_event__process_exit;
2697 trace->tool.fork = perf_event__process_fork;
2698 trace->tool.attr = perf_event__process_attr;
2699 trace->tool.tracing_data = perf_event__process_tracing_data;
2700 trace->tool.build_id = perf_event__process_build_id;
2701
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002702 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002703 trace->tool.ordering_requires_timestamps = true;
2704
2705 /* add tid to output */
2706 trace->multiple_threads = true;
2707
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002708 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002709 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002710 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002711
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002712 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002713 goto out;
2714
David Ahern8fb598e2013-09-28 13:13:00 -06002715 trace->host = &session->machines.host;
2716
David Ahern6810fc92013-08-28 22:29:52 -06002717 err = perf_session__set_tracepoints_handlers(session, handlers);
2718 if (err)
2719 goto out;
2720
Namhyung Kim003824e2013-11-12 15:25:00 +09002721 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2722 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002723 /* older kernels have syscalls tp versus raw_syscalls */
2724 if (evsel == NULL)
2725 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2726 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002727
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002728 if (evsel &&
2729 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2730 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002731 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2732 goto out;
2733 }
2734
2735 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2736 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002737 if (evsel == NULL)
2738 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2739 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002740 if (evsel &&
2741 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2742 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002743 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002744 goto out;
2745 }
2746
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002747 evlist__for_each(session->evlist, evsel) {
2748 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2749 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2750 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2751 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2752 evsel->handler = trace__pgfault;
2753 }
2754
David Ahernbdc89662013-08-28 22:29:53 -06002755 err = parse_target_str(trace);
2756 if (err != 0)
2757 goto out;
2758
David Ahern6810fc92013-08-28 22:29:52 -06002759 setup_pager();
2760
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002761 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002762 if (err)
2763 pr_err("Failed to process events, error %d", err);
2764
David Ahernbf2575c2013-10-08 21:26:53 -06002765 else if (trace->summary)
2766 trace__fprintf_thread_summary(trace, trace->output);
2767
David Ahern6810fc92013-08-28 22:29:52 -06002768out:
2769 perf_session__delete(session);
2770
2771 return err;
2772}
2773
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002774static size_t trace__fprintf_threads_header(FILE *fp)
2775{
2776 size_t printed;
2777
Pekka Enberg99ff7152013-11-12 16:42:14 +02002778 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002779
2780 return printed;
2781}
2782
2783static size_t thread__dump_stats(struct thread_trace *ttrace,
2784 struct trace *trace, FILE *fp)
2785{
2786 struct stats *stats;
2787 size_t printed = 0;
2788 struct syscall *sc;
2789 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2790
2791 if (inode == NULL)
2792 return 0;
2793
2794 printed += fprintf(fp, "\n");
2795
Milian Wolff834fd462015-08-06 11:24:29 +02002796 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2797 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2798 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002799
David Ahernbf2575c2013-10-08 21:26:53 -06002800 /* each int_node is a syscall */
2801 while (inode) {
2802 stats = inode->priv;
2803 if (stats) {
2804 double min = (double)(stats->min) / NSEC_PER_MSEC;
2805 double max = (double)(stats->max) / NSEC_PER_MSEC;
2806 double avg = avg_stats(stats);
2807 double pct;
2808 u64 n = (u64) stats->n;
2809
2810 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2811 avg /= NSEC_PER_MSEC;
2812
2813 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002814 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002815 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
2816 n, avg * n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002817 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002818 }
2819
2820 inode = intlist__next(inode);
2821 }
2822
2823 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002824
2825 return printed;
2826}
2827
David Ahern896cbb52013-09-28 13:12:59 -06002828/* struct used to pass data to per-thread function */
2829struct summary_data {
2830 FILE *fp;
2831 struct trace *trace;
2832 size_t printed;
2833};
2834
2835static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2836{
2837 struct summary_data *data = priv;
2838 FILE *fp = data->fp;
2839 size_t printed = data->printed;
2840 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002841 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002842 double ratio;
2843
2844 if (ttrace == NULL)
2845 return 0;
2846
2847 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2848
Pekka Enberg15e65c62013-11-14 18:43:30 +02002849 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002850 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002851 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002852 if (ttrace->pfmaj)
2853 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2854 if (ttrace->pfmin)
2855 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002856 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002857 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002858
2859 data->printed += printed;
2860
2861 return 0;
2862}
2863
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002864static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2865{
David Ahern896cbb52013-09-28 13:12:59 -06002866 struct summary_data data = {
2867 .fp = fp,
2868 .trace = trace
2869 };
2870 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002871
David Ahern896cbb52013-09-28 13:12:59 -06002872 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002873
David Ahern896cbb52013-09-28 13:12:59 -06002874 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002875}
2876
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002877static int trace__set_duration(const struct option *opt, const char *str,
2878 int unset __maybe_unused)
2879{
2880 struct trace *trace = opt->value;
2881
2882 trace->duration_filter = atof(str);
2883 return 0;
2884}
2885
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002886static int trace__set_filter_pids(const struct option *opt, const char *str,
2887 int unset __maybe_unused)
2888{
2889 int ret = -1;
2890 size_t i;
2891 struct trace *trace = opt->value;
2892 /*
2893 * FIXME: introduce a intarray class, plain parse csv and create a
2894 * { int nr, int entries[] } struct...
2895 */
2896 struct intlist *list = intlist__new(str);
2897
2898 if (list == NULL)
2899 return -1;
2900
2901 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2902 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2903
2904 if (trace->filter_pids.entries == NULL)
2905 goto out;
2906
2907 trace->filter_pids.entries[0] = getpid();
2908
2909 for (i = 1; i < trace->filter_pids.nr; ++i)
2910 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2911
2912 intlist__delete(list);
2913 ret = 0;
2914out:
2915 return ret;
2916}
2917
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002918static int trace__open_output(struct trace *trace, const char *filename)
2919{
2920 struct stat st;
2921
2922 if (!stat(filename, &st) && st.st_size) {
2923 char oldname[PATH_MAX];
2924
2925 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2926 unlink(oldname);
2927 rename(filename, oldname);
2928 }
2929
2930 trace->output = fopen(filename, "w");
2931
2932 return trace->output == NULL ? -errno : 0;
2933}
2934
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002935static int parse_pagefaults(const struct option *opt, const char *str,
2936 int unset __maybe_unused)
2937{
2938 int *trace_pgfaults = opt->value;
2939
2940 if (strcmp(str, "all") == 0)
2941 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2942 else if (strcmp(str, "maj") == 0)
2943 *trace_pgfaults |= TRACE_PFMAJ;
2944 else if (strcmp(str, "min") == 0)
2945 *trace_pgfaults |= TRACE_PFMIN;
2946 else
2947 return -1;
2948
2949 return 0;
2950}
2951
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002952static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2953{
2954 struct perf_evsel *evsel;
2955
2956 evlist__for_each(evlist, evsel)
2957 evsel->handler = handler;
2958}
2959
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002960int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2961{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002962 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002963 "perf trace [<options>] [<command>]",
2964 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002965 "perf trace record [<options>] [<command>]",
2966 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002967 NULL
2968 };
2969 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002970 .audit = {
2971 .machine = audit_detect_machine(),
2972 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2973 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002974 .syscalls = {
2975 . max = -1,
2976 },
2977 .opts = {
2978 .target = {
2979 .uid = UINT_MAX,
2980 .uses_mmap = true,
2981 },
2982 .user_freq = UINT_MAX,
2983 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002984 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002985 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002986 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002987 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002988 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002989 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002990 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002991 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002992 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002993 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002994 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002995 OPT_CALLBACK(0, "event", &trace.evlist, "event",
2996 "event selector. use 'perf list' to list available events",
2997 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002998 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2999 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003000 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03003001 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003002 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003003 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003004 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3005 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003006 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003007 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003008 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3009 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003010 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003011 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003012 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003013 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003014 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003015 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003016 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3017 "number of mmap data pages",
3018 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003019 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003020 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003021 OPT_CALLBACK(0, "duration", &trace, "float",
3022 "show only events with duration > N.M ms",
3023 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003024 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003025 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003026 OPT_BOOLEAN('T', "time", &trace.full_time,
3027 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003028 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3029 "Show only syscall summary with statistics"),
3030 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3031 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003032 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3033 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003034 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003035 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003036 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3037 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003038 OPT_END()
3039 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003040 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003041 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003042 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003043
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003044 signal(SIGSEGV, sighandler_dump_stack);
3045 signal(SIGFPE, sighandler_dump_stack);
3046
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003047 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003048
3049 if (trace.evlist == NULL) {
3050 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003051 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003052 goto out;
3053 }
3054
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003055 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3056 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003057
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003058 if (trace.trace_pgfaults) {
3059 trace.opts.sample_address = true;
3060 trace.opts.sample_time = true;
3061 }
3062
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003063 if (trace.evlist->nr_entries > 0)
3064 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3065
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003066 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3067 return trace__record(&trace, argc-1, &argv[1]);
3068
3069 /* summary_only implies summary option, but don't overwrite summary if set */
3070 if (trace.summary_only)
3071 trace.summary = trace.summary_only;
3072
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003073 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3074 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003075 pr_err("Please specify something to trace.\n");
3076 return -1;
3077 }
3078
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003079 if (output_name != NULL) {
3080 err = trace__open_output(&trace, output_name);
3081 if (err < 0) {
3082 perror("failed to create output file");
3083 goto out;
3084 }
3085 }
3086
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003087 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003088 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003089 struct strlist_config slist_config = {
3090 .dirname = system_path(STRACE_GROUPS_DIR),
3091 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003092
3093 trace.not_ev_qualifier = *s == '!';
3094 if (trace.not_ev_qualifier)
3095 ++s;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003096 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003097 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003098 fputs("Not enough memory to parse event qualifier",
3099 trace.output);
3100 err = -ENOMEM;
3101 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003102 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003103
3104 err = trace__validate_ev_qualifier(&trace);
3105 if (err)
3106 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003107 }
3108
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003109 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003110 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003111 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003112 fprintf(trace.output, "%s", bf);
3113 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003114 }
3115
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003116 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003117 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003118 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003119 fprintf(trace.output, "%s", bf);
3120 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003121 }
3122
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003123 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003124 trace.opts.target.system_wide = true;
3125
David Ahern6810fc92013-08-28 22:29:52 -06003126 if (input_name)
3127 err = trace__replay(&trace);
3128 else
3129 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003130
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003131out_close:
3132 if (output_name != NULL)
3133 fclose(trace.output);
3134out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003135 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003136}