blob: 06cfa93c0305f303be45e3fd9c648e218a95ce10 [file] [log] [blame]
Robert Richter4e319022013-06-11 17:29:18 +02001#include <traceevent/event-parse.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03003#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03004#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03005#include "util/evlist.h"
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03006#include "util/exec_cmd.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03007#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -06008#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03009#include "util/thread.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030010#include "util/parse-options.h"
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030011#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060012#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030013#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060014#include "util/stat.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010015#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070016#include "util/parse-events.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030017
18#include <libaudit.h>
19#include <stdlib.h>
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030020#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030021#include <linux/futex.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030022
Ingo Molnar456857b2013-09-12 15:29:00 +020023/* For older distros: */
24#ifndef MAP_STACK
25# define MAP_STACK 0x20000
26#endif
27
28#ifndef MADV_HWPOISON
29# define MADV_HWPOISON 100
30#endif
31
32#ifndef MADV_MERGEABLE
33# define MADV_MERGEABLE 12
34#endif
35
36#ifndef MADV_UNMERGEABLE
37# define MADV_UNMERGEABLE 13
38#endif
39
Ben Hutchings79d26a62014-02-06 01:00:35 +000040#ifndef EFD_SEMAPHORE
41# define EFD_SEMAPHORE 1
42#endif
43
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030044#ifndef EFD_NONBLOCK
45# define EFD_NONBLOCK 00004000
46#endif
47
48#ifndef EFD_CLOEXEC
49# define EFD_CLOEXEC 02000000
50#endif
51
52#ifndef O_CLOEXEC
53# define O_CLOEXEC 02000000
54#endif
55
56#ifndef SOCK_DCCP
57# define SOCK_DCCP 6
58#endif
59
60#ifndef SOCK_CLOEXEC
61# define SOCK_CLOEXEC 02000000
62#endif
63
64#ifndef SOCK_NONBLOCK
65# define SOCK_NONBLOCK 00004000
66#endif
67
68#ifndef MSG_CMSG_CLOEXEC
69# define MSG_CMSG_CLOEXEC 0x40000000
70#endif
71
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -030072#ifndef PERF_FLAG_FD_NO_GROUP
73# define PERF_FLAG_FD_NO_GROUP (1UL << 0)
74#endif
75
76#ifndef PERF_FLAG_FD_OUTPUT
77# define PERF_FLAG_FD_OUTPUT (1UL << 1)
78#endif
79
80#ifndef PERF_FLAG_PID_CGROUP
81# define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */
82#endif
83
84#ifndef PERF_FLAG_FD_CLOEXEC
85# define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */
86#endif
87
88
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -030089struct tp_field {
90 int offset;
91 union {
92 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
93 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
94 };
95};
96
97#define TP_UINT_FIELD(bits) \
98static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
99{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500100 u##bits value; \
101 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
102 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300103}
104
105TP_UINT_FIELD(8);
106TP_UINT_FIELD(16);
107TP_UINT_FIELD(32);
108TP_UINT_FIELD(64);
109
110#define TP_UINT_FIELD__SWAPPED(bits) \
111static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
112{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500113 u##bits value; \
114 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300115 return bswap_##bits(value);\
116}
117
118TP_UINT_FIELD__SWAPPED(16);
119TP_UINT_FIELD__SWAPPED(32);
120TP_UINT_FIELD__SWAPPED(64);
121
122static int tp_field__init_uint(struct tp_field *field,
123 struct format_field *format_field,
124 bool needs_swap)
125{
126 field->offset = format_field->offset;
127
128 switch (format_field->size) {
129 case 1:
130 field->integer = tp_field__u8;
131 break;
132 case 2:
133 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
134 break;
135 case 4:
136 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
137 break;
138 case 8:
139 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
140 break;
141 default:
142 return -1;
143 }
144
145 return 0;
146}
147
148static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
149{
150 return sample->raw_data + field->offset;
151}
152
153static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
154{
155 field->offset = format_field->offset;
156 field->pointer = tp_field__ptr;
157 return 0;
158}
159
160struct syscall_tp {
161 struct tp_field id;
162 union {
163 struct tp_field args, ret;
164 };
165};
166
167static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
168 struct tp_field *field,
169 const char *name)
170{
171 struct format_field *format_field = perf_evsel__field(evsel, name);
172
173 if (format_field == NULL)
174 return -1;
175
176 return tp_field__init_uint(field, format_field, evsel->needs_swap);
177}
178
179#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
180 ({ struct syscall_tp *sc = evsel->priv;\
181 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
182
183static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
184 struct tp_field *field,
185 const char *name)
186{
187 struct format_field *format_field = perf_evsel__field(evsel, name);
188
189 if (format_field == NULL)
190 return -1;
191
192 return tp_field__init_ptr(field, format_field);
193}
194
195#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
196 ({ struct syscall_tp *sc = evsel->priv;\
197 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
198
199static void perf_evsel__delete_priv(struct perf_evsel *evsel)
200{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300201 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300202 perf_evsel__delete(evsel);
203}
204
Namhyung Kim96695d42013-11-12 08:51:45 -0300205static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
206{
207 evsel->priv = malloc(sizeof(struct syscall_tp));
208 if (evsel->priv != NULL) {
209 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
210 goto out_delete;
211
212 evsel->handler = handler;
213 return 0;
214 }
215
216 return -ENOMEM;
217
218out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300219 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300220 return -ENOENT;
221}
222
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300223static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300224{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300225 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300226
David Ahern9aca7f12013-12-04 19:41:39 -0700227 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
228 if (evsel == NULL)
229 evsel = perf_evsel__newtp("syscalls", direction);
230
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300231 if (evsel) {
Namhyung Kim96695d42013-11-12 08:51:45 -0300232 if (perf_evsel__init_syscall_tp(evsel, handler))
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300233 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300234 }
235
236 return evsel;
237
238out_delete:
239 perf_evsel__delete_priv(evsel);
240 return NULL;
241}
242
243#define perf_evsel__sc_tp_uint(evsel, name, sample) \
244 ({ struct syscall_tp *fields = evsel->priv; \
245 fields->name.integer(&fields->name, sample); })
246
247#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
248 ({ struct syscall_tp *fields = evsel->priv; \
249 fields->name.pointer(&fields->name, sample); })
250
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300251struct syscall_arg {
252 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300253 struct thread *thread;
254 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300255 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300256 u8 idx;
257 u8 mask;
258};
259
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300260struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300261 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300262 int nr_entries;
263 const char **entries;
264};
265
266#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
267 .nr_entries = ARRAY_SIZE(array), \
268 .entries = array, \
269}
270
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300271#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
272 .offset = off, \
273 .nr_entries = ARRAY_SIZE(array), \
274 .entries = array, \
275}
276
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300277static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
278 const char *intfmt,
279 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300280{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300281 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300282 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300283
284 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300285 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300286
287 return scnprintf(bf, size, "%s", sa->entries[idx]);
288}
289
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300290static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
291 struct syscall_arg *arg)
292{
293 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
294}
295
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300296#define SCA_STRARRAY syscall_arg__scnprintf_strarray
297
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300298#if defined(__i386__) || defined(__x86_64__)
299/*
300 * FIXME: Make this available to all arches as soon as the ioctl beautifier
301 * gets rewritten to support all arches.
302 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300303static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
304 struct syscall_arg *arg)
305{
306 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
307}
308
309#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300310#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300311
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300312static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
313 struct syscall_arg *arg);
314
315#define SCA_FD syscall_arg__scnprintf_fd
316
317static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
318 struct syscall_arg *arg)
319{
320 int fd = arg->val;
321
322 if (fd == AT_FDCWD)
323 return scnprintf(bf, size, "CWD");
324
325 return syscall_arg__scnprintf_fd(bf, size, arg);
326}
327
328#define SCA_FDAT syscall_arg__scnprintf_fd_at
329
330static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
331 struct syscall_arg *arg);
332
333#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
334
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300335static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300336 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300337{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300338 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300339}
340
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300341#define SCA_HEX syscall_arg__scnprintf_hex
342
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300343static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
344 struct syscall_arg *arg)
345{
346 return scnprintf(bf, size, "%d", arg->val);
347}
348
349#define SCA_INT syscall_arg__scnprintf_int
350
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300351static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300352 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300353{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300354 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300355
356 if (prot == PROT_NONE)
357 return scnprintf(bf, size, "NONE");
358#define P_MMAP_PROT(n) \
359 if (prot & PROT_##n) { \
360 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
361 prot &= ~PROT_##n; \
362 }
363
364 P_MMAP_PROT(EXEC);
365 P_MMAP_PROT(READ);
366 P_MMAP_PROT(WRITE);
367#ifdef PROT_SEM
368 P_MMAP_PROT(SEM);
369#endif
370 P_MMAP_PROT(GROWSDOWN);
371 P_MMAP_PROT(GROWSUP);
372#undef P_MMAP_PROT
373
374 if (prot)
375 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
376
377 return printed;
378}
379
380#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
381
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300382static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300383 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300384{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300385 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300386
387#define P_MMAP_FLAG(n) \
388 if (flags & MAP_##n) { \
389 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
390 flags &= ~MAP_##n; \
391 }
392
393 P_MMAP_FLAG(SHARED);
394 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400395#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300396 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400397#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300398 P_MMAP_FLAG(ANONYMOUS);
399 P_MMAP_FLAG(DENYWRITE);
400 P_MMAP_FLAG(EXECUTABLE);
401 P_MMAP_FLAG(FILE);
402 P_MMAP_FLAG(FIXED);
403 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600404#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300405 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600406#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300407 P_MMAP_FLAG(LOCKED);
408 P_MMAP_FLAG(NONBLOCK);
409 P_MMAP_FLAG(NORESERVE);
410 P_MMAP_FLAG(POPULATE);
411 P_MMAP_FLAG(STACK);
412#ifdef MAP_UNINITIALIZED
413 P_MMAP_FLAG(UNINITIALIZED);
414#endif
415#undef P_MMAP_FLAG
416
417 if (flags)
418 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
419
420 return printed;
421}
422
423#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
424
Alex Snast86998dd2014-08-13 18:42:40 +0300425static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
426 struct syscall_arg *arg)
427{
428 int printed = 0, flags = arg->val;
429
430#define P_MREMAP_FLAG(n) \
431 if (flags & MREMAP_##n) { \
432 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
433 flags &= ~MREMAP_##n; \
434 }
435
436 P_MREMAP_FLAG(MAYMOVE);
437#ifdef MREMAP_FIXED
438 P_MREMAP_FLAG(FIXED);
439#endif
440#undef P_MREMAP_FLAG
441
442 if (flags)
443 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
444
445 return printed;
446}
447
448#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
449
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300450static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300451 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300452{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300453 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300454
455 switch (behavior) {
456#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
457 P_MADV_BHV(NORMAL);
458 P_MADV_BHV(RANDOM);
459 P_MADV_BHV(SEQUENTIAL);
460 P_MADV_BHV(WILLNEED);
461 P_MADV_BHV(DONTNEED);
462 P_MADV_BHV(REMOVE);
463 P_MADV_BHV(DONTFORK);
464 P_MADV_BHV(DOFORK);
465 P_MADV_BHV(HWPOISON);
466#ifdef MADV_SOFT_OFFLINE
467 P_MADV_BHV(SOFT_OFFLINE);
468#endif
469 P_MADV_BHV(MERGEABLE);
470 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600471#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300472 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600473#endif
474#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300475 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600476#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300477#ifdef MADV_DONTDUMP
478 P_MADV_BHV(DONTDUMP);
479#endif
480#ifdef MADV_DODUMP
481 P_MADV_BHV(DODUMP);
482#endif
483#undef P_MADV_PHV
484 default: break;
485 }
486
487 return scnprintf(bf, size, "%#x", behavior);
488}
489
490#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
491
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300492static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
493 struct syscall_arg *arg)
494{
495 int printed = 0, op = arg->val;
496
497 if (op == 0)
498 return scnprintf(bf, size, "NONE");
499#define P_CMD(cmd) \
500 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
501 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
502 op &= ~LOCK_##cmd; \
503 }
504
505 P_CMD(SH);
506 P_CMD(EX);
507 P_CMD(NB);
508 P_CMD(UN);
509 P_CMD(MAND);
510 P_CMD(RW);
511 P_CMD(READ);
512 P_CMD(WRITE);
513#undef P_OP
514
515 if (op)
516 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
517
518 return printed;
519}
520
521#define SCA_FLOCK syscall_arg__scnprintf_flock
522
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300523static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300524{
525 enum syscall_futex_args {
526 SCF_UADDR = (1 << 0),
527 SCF_OP = (1 << 1),
528 SCF_VAL = (1 << 2),
529 SCF_TIMEOUT = (1 << 3),
530 SCF_UADDR2 = (1 << 4),
531 SCF_VAL3 = (1 << 5),
532 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300533 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300534 int cmd = op & FUTEX_CMD_MASK;
535 size_t printed = 0;
536
537 switch (cmd) {
538#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300539 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
540 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
541 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
542 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
543 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
544 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300545 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300546 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
547 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
548 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
549 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
550 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300551 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
552 default: printed = scnprintf(bf, size, "%#x", cmd); break;
553 }
554
555 if (op & FUTEX_PRIVATE_FLAG)
556 printed += scnprintf(bf + printed, size - printed, "|PRIV");
557
558 if (op & FUTEX_CLOCK_REALTIME)
559 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
560
561 return printed;
562}
563
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300564#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
565
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300566static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
567static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300568
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300569static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
570static DEFINE_STRARRAY(itimers);
571
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300572static const char *whences[] = { "SET", "CUR", "END",
573#ifdef SEEK_DATA
574"DATA",
575#endif
576#ifdef SEEK_HOLE
577"HOLE",
578#endif
579};
580static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300581
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300582static const char *fcntl_cmds[] = {
583 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
584 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
585 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
586 "F_GETOWNER_UIDS",
587};
588static DEFINE_STRARRAY(fcntl_cmds);
589
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300590static const char *rlimit_resources[] = {
591 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
592 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
593 "RTTIME",
594};
595static DEFINE_STRARRAY(rlimit_resources);
596
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300597static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
598static DEFINE_STRARRAY(sighow);
599
David Ahern4f8c1b72013-09-22 19:45:00 -0600600static const char *clockid[] = {
601 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
602 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
603};
604static DEFINE_STRARRAY(clockid);
605
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300606static const char *socket_families[] = {
607 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
608 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
609 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
610 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
611 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
612 "ALG", "NFC", "VSOCK",
613};
614static DEFINE_STRARRAY(socket_families);
615
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300616#ifndef SOCK_TYPE_MASK
617#define SOCK_TYPE_MASK 0xf
618#endif
619
620static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
621 struct syscall_arg *arg)
622{
623 size_t printed;
624 int type = arg->val,
625 flags = type & ~SOCK_TYPE_MASK;
626
627 type &= SOCK_TYPE_MASK;
628 /*
629 * Can't use a strarray, MIPS may override for ABI reasons.
630 */
631 switch (type) {
632#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
633 P_SK_TYPE(STREAM);
634 P_SK_TYPE(DGRAM);
635 P_SK_TYPE(RAW);
636 P_SK_TYPE(RDM);
637 P_SK_TYPE(SEQPACKET);
638 P_SK_TYPE(DCCP);
639 P_SK_TYPE(PACKET);
640#undef P_SK_TYPE
641 default:
642 printed = scnprintf(bf, size, "%#x", type);
643 }
644
645#define P_SK_FLAG(n) \
646 if (flags & SOCK_##n) { \
647 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
648 flags &= ~SOCK_##n; \
649 }
650
651 P_SK_FLAG(CLOEXEC);
652 P_SK_FLAG(NONBLOCK);
653#undef P_SK_FLAG
654
655 if (flags)
656 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
657
658 return printed;
659}
660
661#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
662
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300663#ifndef MSG_PROBE
664#define MSG_PROBE 0x10
665#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600666#ifndef MSG_WAITFORONE
667#define MSG_WAITFORONE 0x10000
668#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300669#ifndef MSG_SENDPAGE_NOTLAST
670#define MSG_SENDPAGE_NOTLAST 0x20000
671#endif
672#ifndef MSG_FASTOPEN
673#define MSG_FASTOPEN 0x20000000
674#endif
675
676static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
677 struct syscall_arg *arg)
678{
679 int printed = 0, flags = arg->val;
680
681 if (flags == 0)
682 return scnprintf(bf, size, "NONE");
683#define P_MSG_FLAG(n) \
684 if (flags & MSG_##n) { \
685 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
686 flags &= ~MSG_##n; \
687 }
688
689 P_MSG_FLAG(OOB);
690 P_MSG_FLAG(PEEK);
691 P_MSG_FLAG(DONTROUTE);
692 P_MSG_FLAG(TRYHARD);
693 P_MSG_FLAG(CTRUNC);
694 P_MSG_FLAG(PROBE);
695 P_MSG_FLAG(TRUNC);
696 P_MSG_FLAG(DONTWAIT);
697 P_MSG_FLAG(EOR);
698 P_MSG_FLAG(WAITALL);
699 P_MSG_FLAG(FIN);
700 P_MSG_FLAG(SYN);
701 P_MSG_FLAG(CONFIRM);
702 P_MSG_FLAG(RST);
703 P_MSG_FLAG(ERRQUEUE);
704 P_MSG_FLAG(NOSIGNAL);
705 P_MSG_FLAG(MORE);
706 P_MSG_FLAG(WAITFORONE);
707 P_MSG_FLAG(SENDPAGE_NOTLAST);
708 P_MSG_FLAG(FASTOPEN);
709 P_MSG_FLAG(CMSG_CLOEXEC);
710#undef P_MSG_FLAG
711
712 if (flags)
713 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
714
715 return printed;
716}
717
718#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
719
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300720static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
721 struct syscall_arg *arg)
722{
723 size_t printed = 0;
724 int mode = arg->val;
725
726 if (mode == F_OK) /* 0 */
727 return scnprintf(bf, size, "F");
728#define P_MODE(n) \
729 if (mode & n##_OK) { \
730 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
731 mode &= ~n##_OK; \
732 }
733
734 P_MODE(R);
735 P_MODE(W);
736 P_MODE(X);
737#undef P_MODE
738
739 if (mode)
740 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
741
742 return printed;
743}
744
745#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
746
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300747static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300748 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300749{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300750 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300751
752 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300753 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300754
755 if (flags == 0)
756 return scnprintf(bf, size, "RDONLY");
757#define P_FLAG(n) \
758 if (flags & O_##n) { \
759 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
760 flags &= ~O_##n; \
761 }
762
763 P_FLAG(APPEND);
764 P_FLAG(ASYNC);
765 P_FLAG(CLOEXEC);
766 P_FLAG(CREAT);
767 P_FLAG(DIRECT);
768 P_FLAG(DIRECTORY);
769 P_FLAG(EXCL);
770 P_FLAG(LARGEFILE);
771 P_FLAG(NOATIME);
772 P_FLAG(NOCTTY);
773#ifdef O_NONBLOCK
774 P_FLAG(NONBLOCK);
775#elif O_NDELAY
776 P_FLAG(NDELAY);
777#endif
778#ifdef O_PATH
779 P_FLAG(PATH);
780#endif
781 P_FLAG(RDWR);
782#ifdef O_DSYNC
783 if ((flags & O_SYNC) == O_SYNC)
784 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
785 else {
786 P_FLAG(DSYNC);
787 }
788#else
789 P_FLAG(SYNC);
790#endif
791 P_FLAG(TRUNC);
792 P_FLAG(WRONLY);
793#undef P_FLAG
794
795 if (flags)
796 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
797
798 return printed;
799}
800
801#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
802
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300803static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size,
804 struct syscall_arg *arg)
805{
806 int printed = 0, flags = arg->val;
807
808 if (flags == 0)
809 return 0;
810
811#define P_FLAG(n) \
812 if (flags & PERF_FLAG_##n) { \
813 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
814 flags &= ~PERF_FLAG_##n; \
815 }
816
817 P_FLAG(FD_NO_GROUP);
818 P_FLAG(FD_OUTPUT);
819 P_FLAG(PID_CGROUP);
820 P_FLAG(FD_CLOEXEC);
821#undef P_FLAG
822
823 if (flags)
824 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
825
826 return printed;
827}
828
829#define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags
830
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300831static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
832 struct syscall_arg *arg)
833{
834 int printed = 0, flags = arg->val;
835
836 if (flags == 0)
837 return scnprintf(bf, size, "NONE");
838#define P_FLAG(n) \
839 if (flags & EFD_##n) { \
840 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
841 flags &= ~EFD_##n; \
842 }
843
844 P_FLAG(SEMAPHORE);
845 P_FLAG(CLOEXEC);
846 P_FLAG(NONBLOCK);
847#undef P_FLAG
848
849 if (flags)
850 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
851
852 return printed;
853}
854
855#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
856
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300857static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
858 struct syscall_arg *arg)
859{
860 int printed = 0, flags = arg->val;
861
862#define P_FLAG(n) \
863 if (flags & O_##n) { \
864 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
865 flags &= ~O_##n; \
866 }
867
868 P_FLAG(CLOEXEC);
869 P_FLAG(NONBLOCK);
870#undef P_FLAG
871
872 if (flags)
873 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
874
875 return printed;
876}
877
878#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
879
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300880static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
881{
882 int sig = arg->val;
883
884 switch (sig) {
885#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
886 P_SIGNUM(HUP);
887 P_SIGNUM(INT);
888 P_SIGNUM(QUIT);
889 P_SIGNUM(ILL);
890 P_SIGNUM(TRAP);
891 P_SIGNUM(ABRT);
892 P_SIGNUM(BUS);
893 P_SIGNUM(FPE);
894 P_SIGNUM(KILL);
895 P_SIGNUM(USR1);
896 P_SIGNUM(SEGV);
897 P_SIGNUM(USR2);
898 P_SIGNUM(PIPE);
899 P_SIGNUM(ALRM);
900 P_SIGNUM(TERM);
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300901 P_SIGNUM(CHLD);
902 P_SIGNUM(CONT);
903 P_SIGNUM(STOP);
904 P_SIGNUM(TSTP);
905 P_SIGNUM(TTIN);
906 P_SIGNUM(TTOU);
907 P_SIGNUM(URG);
908 P_SIGNUM(XCPU);
909 P_SIGNUM(XFSZ);
910 P_SIGNUM(VTALRM);
911 P_SIGNUM(PROF);
912 P_SIGNUM(WINCH);
913 P_SIGNUM(IO);
914 P_SIGNUM(PWR);
915 P_SIGNUM(SYS);
Ben Hutchings02c5bb42014-02-06 01:00:41 +0000916#ifdef SIGEMT
917 P_SIGNUM(EMT);
918#endif
919#ifdef SIGSTKFLT
920 P_SIGNUM(STKFLT);
921#endif
922#ifdef SIGSWI
923 P_SIGNUM(SWI);
924#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300925 default: break;
926 }
927
928 return scnprintf(bf, size, "%#x", sig);
929}
930
931#define SCA_SIGNUM syscall_arg__scnprintf_signum
932
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300933#if defined(__i386__) || defined(__x86_64__)
934/*
935 * FIXME: Make this available to all arches.
936 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300937#define TCGETS 0x5401
938
939static const char *tioctls[] = {
940 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
941 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
942 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
943 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
944 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
945 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
946 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
947 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
948 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
949 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
950 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
951 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
952 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
953 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
954 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
955};
956
957static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300958#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300959
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300960#define STRARRAY(arg, name, array) \
961 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
962 .arg_parm = { [arg] = &strarray__##array, }
963
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300964static struct syscall_fmt {
965 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300966 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300967 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300968 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300969 bool errmsg;
970 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300971 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300972} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300973 { .name = "access", .errmsg = true,
974 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300975 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300976 { .name = "brk", .hexret = true,
977 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600978 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300979 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300980 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300981 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300982 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300983 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300984 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300985 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300986 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300987 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300988 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300989 { .name = "eventfd2", .errmsg = true,
990 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300991 { .name = "faccessat", .errmsg = true,
992 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
993 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300994 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300995 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300996 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300997 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300998 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300999 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001000 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001001 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001002 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001003 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001004 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001005 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001006 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001007 { .name = "fcntl", .errmsg = true,
1008 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1009 [1] = SCA_STRARRAY, /* cmd */ },
1010 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1011 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001012 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -03001013 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001014 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1015 [1] = SCA_FLOCK, /* cmd */ }, },
1016 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001017 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001018 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001019 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001020 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001021 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001022 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001023 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001024 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001025 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001026 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001027 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -03001028 { .name = "futex", .errmsg = true,
1029 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001030 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001031 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001032 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001033 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001034 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001035 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001036 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1037 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001038 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001039 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001040#if defined(__i386__) || defined(__x86_64__)
1041/*
1042 * FIXME: Make this available to all arches.
1043 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001044 [1] = SCA_STRHEXARRAY, /* cmd */
1045 [2] = SCA_HEX, /* arg */ },
1046 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001047#else
1048 [2] = SCA_HEX, /* arg */ }, },
1049#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001050 { .name = "kill", .errmsg = true,
1051 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001052 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001053 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001054 { .name = "lseek", .errmsg = true,
1055 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1056 [2] = SCA_STRARRAY, /* whence */ },
1057 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001058 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001059 { .name = "madvise", .errmsg = true,
1060 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1061 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001062 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001063 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001064 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001065 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001066 { .name = "mlock", .errmsg = true,
1067 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1068 { .name = "mlockall", .errmsg = true,
1069 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001070 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001071 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001072 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001073 [3] = SCA_MMAP_FLAGS, /* flags */
1074 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001075 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001076 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1077 [2] = SCA_MMAP_PROT, /* prot */ }, },
1078 { .name = "mremap", .hexret = true,
1079 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001080 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001081 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001082 { .name = "munlock", .errmsg = true,
1083 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001084 { .name = "munmap", .errmsg = true,
1085 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001086 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001087 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001088 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001089 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001090 { .name = "open", .errmsg = true,
1091 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001092 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001093 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1094 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001095 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001096 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1097 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001098 { .name = "perf_event_open", .errmsg = true,
1099 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1100 [2] = SCA_INT, /* cpu */
1101 [3] = SCA_FD, /* group_fd */
1102 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001103 { .name = "pipe2", .errmsg = true,
1104 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001105 { .name = "poll", .errmsg = true, .timeout = true, },
1106 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001107 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001108 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001109 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001110 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001111 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001112 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001113 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001114 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001115 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001116 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001117 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001118 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001119 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001120 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001121 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001122 { .name = "recvfrom", .errmsg = true,
1123 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1124 { .name = "recvmmsg", .errmsg = true,
1125 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1126 { .name = "recvmsg", .errmsg = true,
1127 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001128 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001129 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001130 { .name = "rt_sigaction", .errmsg = true,
1131 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001132 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001133 { .name = "rt_sigqueueinfo", .errmsg = true,
1134 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1135 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1136 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001137 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001138 { .name = "sendmmsg", .errmsg = true,
1139 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1140 { .name = "sendmsg", .errmsg = true,
1141 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
1142 { .name = "sendto", .errmsg = true,
1143 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001144 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1145 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001146 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001147 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001148 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001149 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1150 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001151 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001152 { .name = "socketpair", .errmsg = true,
1153 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1154 [1] = SCA_SK_TYPE, /* type */ },
1155 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001156 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001157 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001158 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001159 { .name = "tgkill", .errmsg = true,
1160 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1161 { .name = "tkill", .errmsg = true,
1162 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001163 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001164 { .name = "unlinkat", .errmsg = true,
1165 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1166 { .name = "utimensat", .errmsg = true,
1167 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
1168 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001169 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001170 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001171 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001172};
1173
1174static int syscall_fmt__cmp(const void *name, const void *fmtp)
1175{
1176 const struct syscall_fmt *fmt = fmtp;
1177 return strcmp(name, fmt->name);
1178}
1179
1180static struct syscall_fmt *syscall_fmt__find(const char *name)
1181{
1182 const int nmemb = ARRAY_SIZE(syscall_fmts);
1183 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1184}
1185
1186struct syscall {
1187 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001188 int nr_args;
1189 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001190 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001191 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001192 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001193 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001194 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001195};
1196
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001197static size_t fprintf_duration(unsigned long t, FILE *fp)
1198{
1199 double duration = (double)t / NSEC_PER_MSEC;
1200 size_t printed = fprintf(fp, "(");
1201
1202 if (duration >= 1.0)
1203 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1204 else if (duration >= 0.01)
1205 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1206 else
1207 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001208 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001209}
1210
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001211struct thread_trace {
1212 u64 entry_time;
1213 u64 exit_time;
1214 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001215 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001216 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001217 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001218 double runtime_ms;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001219 struct {
1220 int max;
1221 char **table;
1222 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001223
1224 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001225};
1226
1227static struct thread_trace *thread_trace__new(void)
1228{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001229 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1230
1231 if (ttrace)
1232 ttrace->paths.max = -1;
1233
David Ahernbf2575c2013-10-08 21:26:53 -06001234 ttrace->syscall_stats = intlist__new(NULL);
1235
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001236 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001237}
1238
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001239static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001240{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001241 struct thread_trace *ttrace;
1242
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001243 if (thread == NULL)
1244 goto fail;
1245
Namhyung Kim89dceb22014-10-06 09:46:03 +09001246 if (thread__priv(thread) == NULL)
1247 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001248
Namhyung Kim89dceb22014-10-06 09:46:03 +09001249 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001250 goto fail;
1251
Namhyung Kim89dceb22014-10-06 09:46:03 +09001252 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001253 ++ttrace->nr_events;
1254
1255 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001256fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001257 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001258 "WARNING: not enough memory, dropping samples!\n");
1259 return NULL;
1260}
1261
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001262#define TRACE_PFMAJ (1 << 0)
1263#define TRACE_PFMIN (1 << 1)
1264
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001265struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001266 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001267 struct {
1268 int machine;
1269 int open_id;
1270 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001271 struct {
1272 int max;
1273 struct syscall *table;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001274 struct {
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001275 struct perf_evsel *sys_enter,
1276 *sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001277 } events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001278 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001279 struct record_opts opts;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001280 struct perf_evlist *evlist;
David Ahern8fb598e2013-09-28 13:13:00 -06001281 struct machine *host;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001282 struct thread *current;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001283 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001284 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001285 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001286 struct strlist *ev_qualifier;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001287 struct {
1288 size_t nr;
1289 int *entries;
1290 } ev_qualifier_ids;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001291 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -06001292 struct intlist *tid_list;
1293 struct intlist *pid_list;
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08001294 struct {
1295 size_t nr;
1296 pid_t *entries;
1297 } filter_pids;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001298 double duration_filter;
1299 double runtime_ms;
1300 struct {
1301 u64 vfs_getname,
1302 proc_getname;
1303 } stats;
1304 bool not_ev_qualifier;
1305 bool live;
1306 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001307 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001308 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001309 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001310 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001311 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001312 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001313 bool trace_syscalls;
Yunlong Songe366a6d2015-04-02 21:47:18 +08001314 bool force;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001315 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001316};
1317
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001318static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001319{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001320 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001321
1322 if (fd > ttrace->paths.max) {
1323 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1324
1325 if (npath == NULL)
1326 return -1;
1327
1328 if (ttrace->paths.max != -1) {
1329 memset(npath + ttrace->paths.max + 1, 0,
1330 (fd - ttrace->paths.max) * sizeof(char *));
1331 } else {
1332 memset(npath, 0, (fd + 1) * sizeof(char *));
1333 }
1334
1335 ttrace->paths.table = npath;
1336 ttrace->paths.max = fd;
1337 }
1338
1339 ttrace->paths.table[fd] = strdup(pathname);
1340
1341 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1342}
1343
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001344static int thread__read_fd_path(struct thread *thread, int fd)
1345{
1346 char linkname[PATH_MAX], pathname[PATH_MAX];
1347 struct stat st;
1348 int ret;
1349
1350 if (thread->pid_ == thread->tid) {
1351 scnprintf(linkname, sizeof(linkname),
1352 "/proc/%d/fd/%d", thread->pid_, fd);
1353 } else {
1354 scnprintf(linkname, sizeof(linkname),
1355 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1356 }
1357
1358 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1359 return -1;
1360
1361 ret = readlink(linkname, pathname, sizeof(pathname));
1362
1363 if (ret < 0 || ret > st.st_size)
1364 return -1;
1365
1366 pathname[ret] = '\0';
1367 return trace__set_fd_pathname(thread, fd, pathname);
1368}
1369
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001370static const char *thread__fd_path(struct thread *thread, int fd,
1371 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001372{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001373 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001374
1375 if (ttrace == NULL)
1376 return NULL;
1377
1378 if (fd < 0)
1379 return NULL;
1380
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001381 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001382 if (!trace->live)
1383 return NULL;
1384 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001385 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001386 return NULL;
1387 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001388
1389 return ttrace->paths.table[fd];
1390}
1391
1392static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1393 struct syscall_arg *arg)
1394{
1395 int fd = arg->val;
1396 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001397 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001398
1399 if (path)
1400 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1401
1402 return printed;
1403}
1404
1405static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1406 struct syscall_arg *arg)
1407{
1408 int fd = arg->val;
1409 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001410 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001411
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001412 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1413 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001414
1415 return printed;
1416}
1417
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001418static bool trace__filter_duration(struct trace *trace, double t)
1419{
1420 return t < (trace->duration_filter * NSEC_PER_MSEC);
1421}
1422
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001423static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1424{
1425 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1426
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001427 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001428}
1429
Namhyung Kimf15eb532012-10-05 14:02:16 +09001430static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001431static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001432
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001433static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001434{
1435 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001436 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001437}
1438
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001439static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001440 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001441{
1442 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001443 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001444
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001445 if (trace->multiple_threads) {
1446 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001447 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001448 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001449 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001450
1451 return printed;
1452}
1453
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001454static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001455 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001456{
1457 int ret = 0;
1458
1459 switch (event->header.type) {
1460 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001461 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001462 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001463 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001464 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001465 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001466 break;
1467 }
1468
1469 return ret;
1470}
1471
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001472static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001473 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001474 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001475 struct machine *machine)
1476{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001477 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001478 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001479}
1480
1481static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1482{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001483 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001484
1485 if (err)
1486 return err;
1487
David Ahern8fb598e2013-09-28 13:13:00 -06001488 trace->host = machine__new_host();
1489 if (trace->host == NULL)
1490 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001491
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001492 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001493 return -errno;
1494
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001495 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001496 evlist->threads, trace__tool_process, false,
1497 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001498 if (err)
1499 symbol__exit();
1500
1501 return err;
1502}
1503
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001504static int syscall__set_arg_fmts(struct syscall *sc)
1505{
1506 struct format_field *field;
1507 int idx = 0;
1508
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001509 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001510 if (sc->arg_scnprintf == NULL)
1511 return -1;
1512
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001513 if (sc->fmt)
1514 sc->arg_parm = sc->fmt->arg_parm;
1515
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001516 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001517 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1518 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1519 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001520 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1521 ++idx;
1522 }
1523
1524 return 0;
1525}
1526
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001527static int trace__read_syscall_info(struct trace *trace, int id)
1528{
1529 char tp_name[128];
1530 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001531 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001532
1533 if (name == NULL)
1534 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001535
1536 if (id > trace->syscalls.max) {
1537 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1538
1539 if (nsyscalls == NULL)
1540 return -1;
1541
1542 if (trace->syscalls.max != -1) {
1543 memset(nsyscalls + trace->syscalls.max + 1, 0,
1544 (id - trace->syscalls.max) * sizeof(*sc));
1545 } else {
1546 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1547 }
1548
1549 trace->syscalls.table = nsyscalls;
1550 trace->syscalls.max = id;
1551 }
1552
1553 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001554 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001555
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001556 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001557
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001558 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001559 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001560
1561 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1562 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001563 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001564 }
1565
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001566 if (sc->tp_format == NULL)
1567 return -1;
1568
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001569 sc->args = sc->tp_format->format.fields;
1570 sc->nr_args = sc->tp_format->format.nr_fields;
1571 /* drop nr field - not relevant here; does not exist on older kernels */
1572 if (sc->args && strcmp(sc->args->name, "nr") == 0) {
1573 sc->args = sc->args->next;
1574 --sc->nr_args;
1575 }
1576
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001577 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1578
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001579 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001580}
1581
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001582static int trace__validate_ev_qualifier(struct trace *trace)
1583{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001584 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001585 struct str_node *pos;
1586
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001587 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1588 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1589 sizeof(trace->ev_qualifier_ids.entries[0]));
1590
1591 if (trace->ev_qualifier_ids.entries == NULL) {
1592 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1593 trace->output);
1594 err = -EINVAL;
1595 goto out;
1596 }
1597
1598 i = 0;
1599
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001600 strlist__for_each(pos, trace->ev_qualifier) {
1601 const char *sc = pos->s;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001602 int id = audit_name_to_syscall(sc, trace->audit.machine);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001603
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001604 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001605 if (err == 0) {
1606 fputs("Error:\tInvalid syscall ", trace->output);
1607 err = -EINVAL;
1608 } else {
1609 fputs(", ", trace->output);
1610 }
1611
1612 fputs(sc, trace->output);
1613 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001614
1615 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001616 }
1617
1618 if (err < 0) {
1619 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1620 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001621 zfree(&trace->ev_qualifier_ids.entries);
1622 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001623 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001624out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001625 return err;
1626}
1627
David Ahern55d43bc2015-02-19 15:00:22 -05001628/*
1629 * args is to be interpreted as a series of longs but we need to handle
1630 * 8-byte unaligned accesses. args points to raw_data within the event
1631 * and raw_data is guaranteed to be 8-byte unaligned because it is
1632 * preceded by raw_size which is a u32. So we need to copy args to a temp
1633 * variable to read it. Most notably this avoids extended load instructions
1634 * on unaligned addresses
1635 */
1636
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001637static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001638 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001639 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001640{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001641 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001642 unsigned char *p;
1643 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001644
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001645 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001646 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001647 u8 bit = 1;
1648 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001649 .idx = 0,
1650 .mask = 0,
1651 .trace = trace,
1652 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001653 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001654
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001655 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001656 field = field->next, ++arg.idx, bit <<= 1) {
1657 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001658 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001659
1660 /* special care for unaligned accesses */
1661 p = args + sizeof(unsigned long) * arg.idx;
1662 memcpy(&val, p, sizeof(val));
1663
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001664 /*
1665 * Suppress this argument if its value is zero and
1666 * and we don't have a string associated in an
1667 * strarray for it.
1668 */
David Ahern55d43bc2015-02-19 15:00:22 -05001669 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001670 !(sc->arg_scnprintf &&
1671 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1672 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001673 continue;
1674
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001675 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001676 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001677 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001678 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001679 if (sc->arg_parm)
1680 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001681 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1682 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001683 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001684 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001685 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001686 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001687 }
1688 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001689 int i = 0;
1690
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001691 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001692 /* special care for unaligned accesses */
1693 p = args + sizeof(unsigned long) * i;
1694 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001695 printed += scnprintf(bf + printed, size - printed,
1696 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001697 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001698 ++i;
1699 }
1700 }
1701
1702 return printed;
1703}
1704
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001705typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001706 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001707 struct perf_sample *sample);
1708
1709static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001710 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001711{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001712
1713 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001714
1715 /*
1716 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1717 * before that, leaving at a higher verbosity level till that is
1718 * explained. Reproduced with plain ftrace with:
1719 *
1720 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1721 * grep "NR -1 " /t/trace_pipe
1722 *
1723 * After generating some load on the machine.
1724 */
1725 if (verbose > 1) {
1726 static u64 n;
1727 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1728 id, perf_evsel__name(evsel), ++n);
1729 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001730 return NULL;
1731 }
1732
1733 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1734 trace__read_syscall_info(trace, id))
1735 goto out_cant_read;
1736
1737 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1738 goto out_cant_read;
1739
1740 return &trace->syscalls.table[id];
1741
1742out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001743 if (verbose) {
1744 fprintf(trace->output, "Problems reading syscall %d", id);
1745 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1746 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1747 fputs(" information\n", trace->output);
1748 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001749 return NULL;
1750}
1751
David Ahernbf2575c2013-10-08 21:26:53 -06001752static void thread__update_stats(struct thread_trace *ttrace,
1753 int id, struct perf_sample *sample)
1754{
1755 struct int_node *inode;
1756 struct stats *stats;
1757 u64 duration = 0;
1758
1759 inode = intlist__findnew(ttrace->syscall_stats, id);
1760 if (inode == NULL)
1761 return;
1762
1763 stats = inode->priv;
1764 if (stats == NULL) {
1765 stats = malloc(sizeof(struct stats));
1766 if (stats == NULL)
1767 return;
1768 init_stats(stats);
1769 inode->priv = stats;
1770 }
1771
1772 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1773 duration = sample->time - ttrace->entry_time;
1774
1775 update_stats(stats, duration);
1776}
1777
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001778static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1779{
1780 struct thread_trace *ttrace;
1781 u64 duration;
1782 size_t printed;
1783
1784 if (trace->current == NULL)
1785 return 0;
1786
1787 ttrace = thread__priv(trace->current);
1788
1789 if (!ttrace->entry_pending)
1790 return 0;
1791
1792 duration = sample->time - ttrace->entry_time;
1793
1794 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1795 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1796 ttrace->entry_pending = false;
1797
1798 return printed;
1799}
1800
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001801static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001802 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001803 struct perf_sample *sample)
1804{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001805 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001806 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001807 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001808 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001809 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001810 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001811 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001812
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001813 if (sc == NULL)
1814 return -1;
1815
David Ahern8fb598e2013-09-28 13:13:00 -06001816 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001817 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001818 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001819 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001820
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001821 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001822
1823 if (ttrace->entry_str == NULL) {
1824 ttrace->entry_str = malloc(1024);
1825 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001826 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001827 }
1828
David Ahern13f22a22015-03-19 12:23:03 -06001829 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001830 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001831
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001832 ttrace->entry_time = sample->time;
1833 msg = ttrace->entry_str;
1834 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1835
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001836 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1837 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001838
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001839 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001840 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001841 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1842 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001843 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001844 } else
1845 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001846
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001847 if (trace->current != thread) {
1848 thread__put(trace->current);
1849 trace->current = thread__get(thread);
1850 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001851 err = 0;
1852out_put:
1853 thread__put(thread);
1854 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001855}
1856
1857static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001858 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001859 struct perf_sample *sample)
1860{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001861 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001862 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001863 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001864 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001865 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001866 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001867
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001868 if (sc == NULL)
1869 return -1;
1870
David Ahern8fb598e2013-09-28 13:13:00 -06001871 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001872 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001873 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001874 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001875
David Ahernbf2575c2013-10-08 21:26:53 -06001876 if (trace->summary)
1877 thread__update_stats(ttrace, id, sample);
1878
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001879 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001880
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001881 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1882 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1883 trace->last_vfs_getname = NULL;
1884 ++trace->stats.vfs_getname;
1885 }
1886
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001887 ttrace->exit_time = sample->time;
1888
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001889 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001890 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001891 if (trace__filter_duration(trace, duration))
1892 goto out;
1893 } else if (trace->duration_filter)
1894 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001895
David Ahernfd2eaba2013-11-12 09:31:15 -07001896 if (trace->summary_only)
1897 goto out;
1898
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001899 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001900
1901 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001902 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001903 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001904 fprintf(trace->output, " ... [");
1905 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1906 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001907 }
1908
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001909 if (sc->fmt == NULL) {
1910signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001911 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001912 } else if (ret < 0 && sc->fmt->errmsg) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001913 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001914 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1915 *e = audit_errno_to_name(-ret);
1916
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001917 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001918 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001919 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001920 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001921 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001922 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001923 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001924
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001925 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001926out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001927 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001928 err = 0;
1929out_put:
1930 thread__put(thread);
1931 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001932}
1933
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001934static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001935 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001936 struct perf_sample *sample)
1937{
1938 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1939 return 0;
1940}
1941
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001942static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001943 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001944 struct perf_sample *sample)
1945{
1946 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1947 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001948 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001949 sample->pid,
1950 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001951 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001952
1953 if (ttrace == NULL)
1954 goto out_dump;
1955
1956 ttrace->runtime_ms += runtime_ms;
1957 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001958 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001959 return 0;
1960
1961out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001962 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001963 evsel->name,
1964 perf_evsel__strval(evsel, sample, "comm"),
1965 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1966 runtime,
1967 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001968 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001969 return 0;
1970}
1971
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001972static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1973 union perf_event *event __maybe_unused,
1974 struct perf_sample *sample)
1975{
1976 trace__printf_interrupted_entry(trace, sample);
1977 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001978
1979 if (trace->trace_syscalls)
1980 fprintf(trace->output, "( ): ");
1981
1982 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001983
1984 if (evsel->tp_format) {
1985 event_format__fprintf(evsel->tp_format, sample->cpu,
1986 sample->raw_data, sample->raw_size,
1987 trace->output);
1988 }
1989
1990 fprintf(trace->output, ")\n");
1991 return 0;
1992}
1993
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001994static void print_location(FILE *f, struct perf_sample *sample,
1995 struct addr_location *al,
1996 bool print_dso, bool print_sym)
1997{
1998
1999 if ((verbose || print_dso) && al->map)
2000 fprintf(f, "%s@", al->map->dso->long_name);
2001
2002 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002003 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002004 al->addr - al->sym->start);
2005 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002006 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002007 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002008 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002009}
2010
2011static int trace__pgfault(struct trace *trace,
2012 struct perf_evsel *evsel,
2013 union perf_event *event,
2014 struct perf_sample *sample)
2015{
2016 struct thread *thread;
2017 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
2018 struct addr_location al;
2019 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002020 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002021 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002022
2023 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002024 ttrace = thread__trace(thread, trace->output);
2025 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002026 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002027
2028 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2029 ttrace->pfmaj++;
2030 else
2031 ttrace->pfmin++;
2032
2033 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002034 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002035
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002036 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002037 sample->ip, &al);
2038
2039 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2040
2041 fprintf(trace->output, "%sfault [",
2042 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2043 "maj" : "min");
2044
2045 print_location(trace->output, sample, &al, false, true);
2046
2047 fprintf(trace->output, "] => ");
2048
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002049 thread__find_addr_location(thread, cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002050 sample->addr, &al);
2051
2052 if (!al.map) {
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002053 thread__find_addr_location(thread, cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002054 MAP__FUNCTION, sample->addr, &al);
2055
2056 if (al.map)
2057 map_type = 'x';
2058 else
2059 map_type = '?';
2060 }
2061
2062 print_location(trace->output, sample, &al, true, false);
2063
2064 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002065out:
2066 err = 0;
2067out_put:
2068 thread__put(thread);
2069 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002070}
2071
David Ahernbdc89662013-08-28 22:29:53 -06002072static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2073{
2074 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2075 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2076 return false;
2077
2078 if (trace->pid_list || trace->tid_list)
2079 return true;
2080
2081 return false;
2082}
2083
David Ahern6810fc92013-08-28 22:29:52 -06002084static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002085 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002086 struct perf_sample *sample,
2087 struct perf_evsel *evsel,
2088 struct machine *machine __maybe_unused)
2089{
2090 struct trace *trace = container_of(tool, struct trace, tool);
2091 int err = 0;
2092
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002093 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002094
David Ahernbdc89662013-08-28 22:29:53 -06002095 if (skip_sample(trace, sample))
2096 return 0;
2097
David Ahern4bb09192013-09-04 12:37:43 -06002098 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06002099 trace->base_time = sample->time;
2100
David Ahern31605652013-12-04 19:41:41 -07002101 if (handler) {
2102 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002103 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002104 }
David Ahern6810fc92013-08-28 22:29:52 -06002105
2106 return err;
2107}
2108
David Ahernbdc89662013-08-28 22:29:53 -06002109static int parse_target_str(struct trace *trace)
2110{
2111 if (trace->opts.target.pid) {
2112 trace->pid_list = intlist__new(trace->opts.target.pid);
2113 if (trace->pid_list == NULL) {
2114 pr_err("Error parsing process id string\n");
2115 return -EINVAL;
2116 }
2117 }
2118
2119 if (trace->opts.target.tid) {
2120 trace->tid_list = intlist__new(trace->opts.target.tid);
2121 if (trace->tid_list == NULL) {
2122 pr_err("Error parsing thread id string\n");
2123 return -EINVAL;
2124 }
2125 }
2126
2127 return 0;
2128}
2129
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002130static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002131{
2132 unsigned int rec_argc, i, j;
2133 const char **rec_argv;
2134 const char * const record_args[] = {
2135 "record",
2136 "-R",
2137 "-m", "1024",
2138 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002139 };
2140
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002141 const char * const sc_args[] = { "-e", };
2142 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2143 const char * const majpf_args[] = { "-e", "major-faults" };
2144 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2145 const char * const minpf_args[] = { "-e", "minor-faults" };
2146 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2147
David Ahern9aca7f12013-12-04 19:41:39 -07002148 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002149 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2150 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002151 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2152
2153 if (rec_argv == NULL)
2154 return -ENOMEM;
2155
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002156 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002157 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002158 rec_argv[j++] = record_args[i];
2159
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002160 if (trace->trace_syscalls) {
2161 for (i = 0; i < sc_args_nr; i++)
2162 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002163
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002164 /* event string may be different for older kernels - e.g., RHEL6 */
2165 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2166 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2167 else if (is_valid_tracepoint("syscalls:sys_enter"))
2168 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2169 else {
2170 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2171 return -1;
2172 }
David Ahern9aca7f12013-12-04 19:41:39 -07002173 }
David Ahern9aca7f12013-12-04 19:41:39 -07002174
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002175 if (trace->trace_pgfaults & TRACE_PFMAJ)
2176 for (i = 0; i < majpf_args_nr; i++)
2177 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002178
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002179 if (trace->trace_pgfaults & TRACE_PFMIN)
2180 for (i = 0; i < minpf_args_nr; i++)
2181 rec_argv[j++] = minpf_args[i];
2182
2183 for (i = 0; i < (unsigned int)argc; i++)
2184 rec_argv[j++] = argv[i];
2185
2186 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002187}
2188
David Ahernbf2575c2013-10-08 21:26:53 -06002189static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2190
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002191static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
2192{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002193 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002194 if (evsel == NULL)
2195 return;
2196
2197 if (perf_evsel__field(evsel, "pathname") == NULL) {
2198 perf_evsel__delete(evsel);
2199 return;
2200 }
2201
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002202 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002203 perf_evlist__add(evlist, evsel);
2204}
2205
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002206static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2207 u64 config)
2208{
2209 struct perf_evsel *evsel;
2210 struct perf_event_attr attr = {
2211 .type = PERF_TYPE_SOFTWARE,
2212 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002213 };
2214
2215 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002216 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002217
2218 event_attr_init(&attr);
2219
2220 evsel = perf_evsel__new(&attr);
2221 if (!evsel)
2222 return -ENOMEM;
2223
2224 evsel->handler = trace__pgfault;
2225 perf_evlist__add(evlist, evsel);
2226
2227 return 0;
2228}
2229
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002230static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2231{
2232 const u32 type = event->header.type;
2233 struct perf_evsel *evsel;
2234
2235 if (!trace->full_time && trace->base_time == 0)
2236 trace->base_time = sample->time;
2237
2238 if (type != PERF_RECORD_SAMPLE) {
2239 trace__process_event(trace, trace->host, event, sample);
2240 return;
2241 }
2242
2243 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2244 if (evsel == NULL) {
2245 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2246 return;
2247 }
2248
2249 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2250 sample->raw_data == NULL) {
2251 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2252 perf_evsel__name(evsel), sample->tid,
2253 sample->cpu, sample->raw_size);
2254 } else {
2255 tracepoint_handler handler = evsel->handler;
2256 handler(trace, evsel, event, sample);
2257 }
2258}
2259
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002260static int trace__add_syscall_newtp(struct trace *trace)
2261{
2262 int ret = -1;
2263 struct perf_evlist *evlist = trace->evlist;
2264 struct perf_evsel *sys_enter, *sys_exit;
2265
2266 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2267 if (sys_enter == NULL)
2268 goto out;
2269
2270 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2271 goto out_delete_sys_enter;
2272
2273 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2274 if (sys_exit == NULL)
2275 goto out_delete_sys_enter;
2276
2277 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2278 goto out_delete_sys_exit;
2279
2280 perf_evlist__add(evlist, sys_enter);
2281 perf_evlist__add(evlist, sys_exit);
2282
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002283 trace->syscalls.events.sys_enter = sys_enter;
2284 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002285
2286 ret = 0;
2287out:
2288 return ret;
2289
2290out_delete_sys_exit:
2291 perf_evsel__delete_priv(sys_exit);
2292out_delete_sys_enter:
2293 perf_evsel__delete_priv(sys_enter);
2294 goto out;
2295}
2296
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002297static int trace__set_ev_qualifier_filter(struct trace *trace)
2298{
2299 int err = -1;
2300 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2301 trace->ev_qualifier_ids.nr,
2302 trace->ev_qualifier_ids.entries);
2303
2304 if (filter == NULL)
2305 goto out_enomem;
2306
2307 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2308 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2309
2310 free(filter);
2311out:
2312 return err;
2313out_enomem:
2314 errno = ENOMEM;
2315 goto out;
2316}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002317
Namhyung Kimf15eb532012-10-05 14:02:16 +09002318static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002319{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002320 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002321 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002322 int err = -1, i;
2323 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002324 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002325 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002326
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002327 trace->live = true;
2328
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002329 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002330 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002331
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002332 if (trace->trace_syscalls)
2333 perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002334
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002335 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002336 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002337 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002338 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002339
2340 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2341 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002342 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002343
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002344 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002345 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2346 trace__sched_stat_runtime))
2347 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002348
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002349 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2350 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002351 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002352 goto out_delete_evlist;
2353 }
2354
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002355 err = trace__symbols_init(trace, evlist);
2356 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002357 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002358 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002359 }
2360
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002361 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002362
Namhyung Kimf15eb532012-10-05 14:02:16 +09002363 signal(SIGCHLD, sig_handler);
2364 signal(SIGINT, sig_handler);
2365
2366 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002367 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002368 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002369 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002370 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002371 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002372 }
2373 }
2374
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002375 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002376 if (err < 0)
2377 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002378
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002379 /*
2380 * Better not use !target__has_task() here because we need to cover the
2381 * case where no threads were specified in the command line, but a
2382 * workload was, and in that case we will fill in the thread_map when
2383 * we fork the workload in perf_evlist__prepare_workload.
2384 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002385 if (trace->filter_pids.nr > 0)
2386 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002387 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002388 err = perf_evlist__set_filter_pid(evlist, getpid());
2389
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002390 if (err < 0)
2391 goto out_error_mem;
2392
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002393 if (trace->ev_qualifier_ids.nr > 0) {
2394 err = trace__set_ev_qualifier_filter(trace);
2395 if (err < 0)
2396 goto out_errno;
2397 }
2398
2399 pr_debug("%s\n", trace->syscalls.events.sys_exit->filter);
2400
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002401 err = perf_evlist__apply_filters(evlist, &evsel);
2402 if (err < 0)
2403 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002404
Jiri Olsaf8850372013-11-28 17:57:22 +01002405 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002406 if (err < 0)
2407 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002408
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002409 if (!target__none(&trace->opts.target))
2410 perf_evlist__enable(evlist);
2411
Namhyung Kimf15eb532012-10-05 14:02:16 +09002412 if (forks)
2413 perf_evlist__start_workload(evlist);
2414
Jiri Olsae13798c2015-06-23 00:36:02 +02002415 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002416 evlist->threads->nr > 1 ||
2417 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002418again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002419 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002420
2421 for (i = 0; i < evlist->nr_mmaps; i++) {
2422 union perf_event *event;
2423
2424 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002425 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002426
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002427 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002428
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002429 err = perf_evlist__parse_sample(evlist, event, &sample);
2430 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002431 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002432 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002433 }
2434
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002435 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002436next_event:
2437 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002438
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002439 if (interrupted)
2440 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002441
2442 if (done && !draining) {
2443 perf_evlist__disable(evlist);
2444 draining = true;
2445 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002446 }
2447 }
2448
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002449 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002450 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002451
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002452 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2453 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2454 draining = true;
2455
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002456 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002457 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002458 } else {
2459 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002460 }
2461
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002462out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002463 thread__zput(trace->current);
2464
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002465 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002466
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002467 if (!err) {
2468 if (trace->summary)
2469 trace__fprintf_thread_summary(trace, trace->output);
2470
2471 if (trace->show_tool_stats) {
2472 fprintf(trace->output, "Stats:\n "
2473 " vfs_getname : %" PRIu64 "\n"
2474 " proc_getname: %" PRIu64 "\n",
2475 trace->stats.vfs_getname,
2476 trace->stats.proc_getname);
2477 }
2478 }
David Ahernbf2575c2013-10-08 21:26:53 -06002479
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002480out_delete_evlist:
2481 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002482 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002483 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002484 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002485{
2486 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002487
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002488out_error_sched_stat_runtime:
2489 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
2490 goto out_error;
2491
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002492out_error_raw_syscalls:
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002493 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002494 goto out_error;
2495
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002496out_error_mmap:
2497 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2498 goto out_error;
2499
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002500out_error_open:
2501 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2502
2503out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002504 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302505 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002506
2507out_error_apply_filters:
2508 fprintf(trace->output,
2509 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2510 evsel->filter, perf_evsel__name(evsel), errno,
2511 strerror_r(errno, errbuf, sizeof(errbuf)));
2512 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002513}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002514out_error_mem:
2515 fprintf(trace->output, "Not enough memory to run!\n");
2516 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002517
2518out_errno:
2519 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2520 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002521}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002522
David Ahern6810fc92013-08-28 22:29:52 -06002523static int trace__replay(struct trace *trace)
2524{
2525 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002526 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002527 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002528 struct perf_data_file file = {
2529 .path = input_name,
2530 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002531 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002532 };
David Ahern6810fc92013-08-28 22:29:52 -06002533 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002534 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002535 int err = -1;
2536
2537 trace->tool.sample = trace__process_sample;
2538 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002539 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002540 trace->tool.comm = perf_event__process_comm;
2541 trace->tool.exit = perf_event__process_exit;
2542 trace->tool.fork = perf_event__process_fork;
2543 trace->tool.attr = perf_event__process_attr;
2544 trace->tool.tracing_data = perf_event__process_tracing_data;
2545 trace->tool.build_id = perf_event__process_build_id;
2546
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002547 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002548 trace->tool.ordering_requires_timestamps = true;
2549
2550 /* add tid to output */
2551 trace->multiple_threads = true;
2552
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002553 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002554 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002555 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002556
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002557 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002558 goto out;
2559
David Ahern8fb598e2013-09-28 13:13:00 -06002560 trace->host = &session->machines.host;
2561
David Ahern6810fc92013-08-28 22:29:52 -06002562 err = perf_session__set_tracepoints_handlers(session, handlers);
2563 if (err)
2564 goto out;
2565
Namhyung Kim003824e2013-11-12 15:25:00 +09002566 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2567 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002568 /* older kernels have syscalls tp versus raw_syscalls */
2569 if (evsel == NULL)
2570 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2571 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002572
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002573 if (evsel &&
2574 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2575 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002576 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2577 goto out;
2578 }
2579
2580 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2581 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002582 if (evsel == NULL)
2583 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2584 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002585 if (evsel &&
2586 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2587 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002588 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002589 goto out;
2590 }
2591
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002592 evlist__for_each(session->evlist, evsel) {
2593 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2594 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2595 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2596 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2597 evsel->handler = trace__pgfault;
2598 }
2599
David Ahernbdc89662013-08-28 22:29:53 -06002600 err = parse_target_str(trace);
2601 if (err != 0)
2602 goto out;
2603
David Ahern6810fc92013-08-28 22:29:52 -06002604 setup_pager();
2605
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002606 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002607 if (err)
2608 pr_err("Failed to process events, error %d", err);
2609
David Ahernbf2575c2013-10-08 21:26:53 -06002610 else if (trace->summary)
2611 trace__fprintf_thread_summary(trace, trace->output);
2612
David Ahern6810fc92013-08-28 22:29:52 -06002613out:
2614 perf_session__delete(session);
2615
2616 return err;
2617}
2618
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002619static size_t trace__fprintf_threads_header(FILE *fp)
2620{
2621 size_t printed;
2622
Pekka Enberg99ff7152013-11-12 16:42:14 +02002623 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002624
2625 return printed;
2626}
2627
2628static size_t thread__dump_stats(struct thread_trace *ttrace,
2629 struct trace *trace, FILE *fp)
2630{
2631 struct stats *stats;
2632 size_t printed = 0;
2633 struct syscall *sc;
2634 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2635
2636 if (inode == NULL)
2637 return 0;
2638
2639 printed += fprintf(fp, "\n");
2640
Pekka Enberg27a778b2013-11-13 14:21:48 +02002641 printed += fprintf(fp, " syscall calls min avg max stddev\n");
2642 printed += fprintf(fp, " (msec) (msec) (msec) (%%)\n");
2643 printed += fprintf(fp, " --------------- -------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002644
David Ahernbf2575c2013-10-08 21:26:53 -06002645 /* each int_node is a syscall */
2646 while (inode) {
2647 stats = inode->priv;
2648 if (stats) {
2649 double min = (double)(stats->min) / NSEC_PER_MSEC;
2650 double max = (double)(stats->max) / NSEC_PER_MSEC;
2651 double avg = avg_stats(stats);
2652 double pct;
2653 u64 n = (u64) stats->n;
2654
2655 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2656 avg /= NSEC_PER_MSEC;
2657
2658 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002659 printed += fprintf(fp, " %-15s", sc->name);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002660 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f",
Pekka Enberg7f7a4132013-11-12 16:10:10 +02002661 n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002662 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002663 }
2664
2665 inode = intlist__next(inode);
2666 }
2667
2668 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002669
2670 return printed;
2671}
2672
David Ahern896cbb52013-09-28 13:12:59 -06002673/* struct used to pass data to per-thread function */
2674struct summary_data {
2675 FILE *fp;
2676 struct trace *trace;
2677 size_t printed;
2678};
2679
2680static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2681{
2682 struct summary_data *data = priv;
2683 FILE *fp = data->fp;
2684 size_t printed = data->printed;
2685 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002686 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002687 double ratio;
2688
2689 if (ttrace == NULL)
2690 return 0;
2691
2692 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2693
Pekka Enberg15e65c62013-11-14 18:43:30 +02002694 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002695 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002696 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002697 if (ttrace->pfmaj)
2698 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2699 if (ttrace->pfmin)
2700 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002701 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002702 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002703
2704 data->printed += printed;
2705
2706 return 0;
2707}
2708
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002709static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2710{
David Ahern896cbb52013-09-28 13:12:59 -06002711 struct summary_data data = {
2712 .fp = fp,
2713 .trace = trace
2714 };
2715 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002716
David Ahern896cbb52013-09-28 13:12:59 -06002717 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002718
David Ahern896cbb52013-09-28 13:12:59 -06002719 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002720}
2721
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002722static int trace__set_duration(const struct option *opt, const char *str,
2723 int unset __maybe_unused)
2724{
2725 struct trace *trace = opt->value;
2726
2727 trace->duration_filter = atof(str);
2728 return 0;
2729}
2730
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002731static int trace__set_filter_pids(const struct option *opt, const char *str,
2732 int unset __maybe_unused)
2733{
2734 int ret = -1;
2735 size_t i;
2736 struct trace *trace = opt->value;
2737 /*
2738 * FIXME: introduce a intarray class, plain parse csv and create a
2739 * { int nr, int entries[] } struct...
2740 */
2741 struct intlist *list = intlist__new(str);
2742
2743 if (list == NULL)
2744 return -1;
2745
2746 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2747 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2748
2749 if (trace->filter_pids.entries == NULL)
2750 goto out;
2751
2752 trace->filter_pids.entries[0] = getpid();
2753
2754 for (i = 1; i < trace->filter_pids.nr; ++i)
2755 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2756
2757 intlist__delete(list);
2758 ret = 0;
2759out:
2760 return ret;
2761}
2762
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002763static int trace__open_output(struct trace *trace, const char *filename)
2764{
2765 struct stat st;
2766
2767 if (!stat(filename, &st) && st.st_size) {
2768 char oldname[PATH_MAX];
2769
2770 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2771 unlink(oldname);
2772 rename(filename, oldname);
2773 }
2774
2775 trace->output = fopen(filename, "w");
2776
2777 return trace->output == NULL ? -errno : 0;
2778}
2779
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002780static int parse_pagefaults(const struct option *opt, const char *str,
2781 int unset __maybe_unused)
2782{
2783 int *trace_pgfaults = opt->value;
2784
2785 if (strcmp(str, "all") == 0)
2786 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2787 else if (strcmp(str, "maj") == 0)
2788 *trace_pgfaults |= TRACE_PFMAJ;
2789 else if (strcmp(str, "min") == 0)
2790 *trace_pgfaults |= TRACE_PFMIN;
2791 else
2792 return -1;
2793
2794 return 0;
2795}
2796
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002797static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2798{
2799 struct perf_evsel *evsel;
2800
2801 evlist__for_each(evlist, evsel)
2802 evsel->handler = handler;
2803}
2804
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002805int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2806{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002807 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002808 "perf trace [<options>] [<command>]",
2809 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002810 "perf trace record [<options>] [<command>]",
2811 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002812 NULL
2813 };
2814 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002815 .audit = {
2816 .machine = audit_detect_machine(),
2817 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2818 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002819 .syscalls = {
2820 . max = -1,
2821 },
2822 .opts = {
2823 .target = {
2824 .uid = UINT_MAX,
2825 .uses_mmap = true,
2826 },
2827 .user_freq = UINT_MAX,
2828 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002829 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002830 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002831 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002832 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002833 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002834 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002835 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002836 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002837 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002838 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002839 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002840 OPT_CALLBACK(0, "event", &trace.evlist, "event",
2841 "event selector. use 'perf list' to list available events",
2842 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002843 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2844 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002845 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03002846 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002847 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002848 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002849 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2850 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002851 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002852 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002853 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2854 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002855 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002856 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002857 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002858 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002859 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002860 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002861 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2862 "number of mmap data pages",
2863 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002864 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002865 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002866 OPT_CALLBACK(0, "duration", &trace, "float",
2867 "show only events with duration > N.M ms",
2868 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002869 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002870 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002871 OPT_BOOLEAN('T', "time", &trace.full_time,
2872 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002873 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2874 "Show only syscall summary with statistics"),
2875 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2876 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002877 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2878 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002879 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002880 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Kan Liang9d9cad72015-06-17 09:51:11 -04002881 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2882 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002883 OPT_END()
2884 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002885 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002886 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002887 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002888
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002889 signal(SIGSEGV, sighandler_dump_stack);
2890 signal(SIGFPE, sighandler_dump_stack);
2891
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002892 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002893
2894 if (trace.evlist == NULL) {
2895 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002896 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002897 goto out;
2898 }
2899
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002900 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2901 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002902
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002903 if (trace.trace_pgfaults) {
2904 trace.opts.sample_address = true;
2905 trace.opts.sample_time = true;
2906 }
2907
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002908 if (trace.evlist->nr_entries > 0)
2909 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2910
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002911 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2912 return trace__record(&trace, argc-1, &argv[1]);
2913
2914 /* summary_only implies summary option, but don't overwrite summary if set */
2915 if (trace.summary_only)
2916 trace.summary = trace.summary_only;
2917
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002918 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2919 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002920 pr_err("Please specify something to trace.\n");
2921 return -1;
2922 }
2923
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002924 if (output_name != NULL) {
2925 err = trace__open_output(&trace, output_name);
2926 if (err < 0) {
2927 perror("failed to create output file");
2928 goto out;
2929 }
2930 }
2931
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002932 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002933 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03002934 struct strlist_config slist_config = {
2935 .dirname = system_path(STRACE_GROUPS_DIR),
2936 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002937
2938 trace.not_ev_qualifier = *s == '!';
2939 if (trace.not_ev_qualifier)
2940 ++s;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03002941 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002942 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002943 fputs("Not enough memory to parse event qualifier",
2944 trace.output);
2945 err = -ENOMEM;
2946 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002947 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03002948
2949 err = trace__validate_ev_qualifier(&trace);
2950 if (err)
2951 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002952 }
2953
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002954 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002955 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002956 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002957 fprintf(trace.output, "%s", bf);
2958 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002959 }
2960
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002961 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002962 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002963 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002964 fprintf(trace.output, "%s", bf);
2965 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002966 }
2967
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002968 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002969 trace.opts.target.system_wide = true;
2970
David Ahern6810fc92013-08-28 22:29:52 -06002971 if (input_name)
2972 err = trace__replay(&trace);
2973 else
2974 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002975
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002976out_close:
2977 if (output_name != NULL)
2978 fclose(trace.output);
2979out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002980 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002981}