blob: 489cc118a36aea132a39827532b998c9fb37c0d8 [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 Melob62bee12015-08-11 11:05:36 -0300572static const char *keyctl_options[] = {
573 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
574 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
575 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
576 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
577 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
578};
579static DEFINE_STRARRAY(keyctl_options);
580
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300581static const char *whences[] = { "SET", "CUR", "END",
582#ifdef SEEK_DATA
583"DATA",
584#endif
585#ifdef SEEK_HOLE
586"HOLE",
587#endif
588};
589static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300590
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300591static const char *fcntl_cmds[] = {
592 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
593 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
594 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
595 "F_GETOWNER_UIDS",
596};
597static DEFINE_STRARRAY(fcntl_cmds);
598
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300599static const char *rlimit_resources[] = {
600 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
601 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
602 "RTTIME",
603};
604static DEFINE_STRARRAY(rlimit_resources);
605
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300606static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
607static DEFINE_STRARRAY(sighow);
608
David Ahern4f8c1b72013-09-22 19:45:00 -0600609static const char *clockid[] = {
610 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300611 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
612 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600613};
614static DEFINE_STRARRAY(clockid);
615
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300616static const char *socket_families[] = {
617 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
618 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
619 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
620 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
621 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
622 "ALG", "NFC", "VSOCK",
623};
624static DEFINE_STRARRAY(socket_families);
625
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300626#ifndef SOCK_TYPE_MASK
627#define SOCK_TYPE_MASK 0xf
628#endif
629
630static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
631 struct syscall_arg *arg)
632{
633 size_t printed;
634 int type = arg->val,
635 flags = type & ~SOCK_TYPE_MASK;
636
637 type &= SOCK_TYPE_MASK;
638 /*
639 * Can't use a strarray, MIPS may override for ABI reasons.
640 */
641 switch (type) {
642#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
643 P_SK_TYPE(STREAM);
644 P_SK_TYPE(DGRAM);
645 P_SK_TYPE(RAW);
646 P_SK_TYPE(RDM);
647 P_SK_TYPE(SEQPACKET);
648 P_SK_TYPE(DCCP);
649 P_SK_TYPE(PACKET);
650#undef P_SK_TYPE
651 default:
652 printed = scnprintf(bf, size, "%#x", type);
653 }
654
655#define P_SK_FLAG(n) \
656 if (flags & SOCK_##n) { \
657 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
658 flags &= ~SOCK_##n; \
659 }
660
661 P_SK_FLAG(CLOEXEC);
662 P_SK_FLAG(NONBLOCK);
663#undef P_SK_FLAG
664
665 if (flags)
666 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
667
668 return printed;
669}
670
671#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
672
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300673#ifndef MSG_PROBE
674#define MSG_PROBE 0x10
675#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600676#ifndef MSG_WAITFORONE
677#define MSG_WAITFORONE 0x10000
678#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300679#ifndef MSG_SENDPAGE_NOTLAST
680#define MSG_SENDPAGE_NOTLAST 0x20000
681#endif
682#ifndef MSG_FASTOPEN
683#define MSG_FASTOPEN 0x20000000
684#endif
685
686static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
687 struct syscall_arg *arg)
688{
689 int printed = 0, flags = arg->val;
690
691 if (flags == 0)
692 return scnprintf(bf, size, "NONE");
693#define P_MSG_FLAG(n) \
694 if (flags & MSG_##n) { \
695 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
696 flags &= ~MSG_##n; \
697 }
698
699 P_MSG_FLAG(OOB);
700 P_MSG_FLAG(PEEK);
701 P_MSG_FLAG(DONTROUTE);
702 P_MSG_FLAG(TRYHARD);
703 P_MSG_FLAG(CTRUNC);
704 P_MSG_FLAG(PROBE);
705 P_MSG_FLAG(TRUNC);
706 P_MSG_FLAG(DONTWAIT);
707 P_MSG_FLAG(EOR);
708 P_MSG_FLAG(WAITALL);
709 P_MSG_FLAG(FIN);
710 P_MSG_FLAG(SYN);
711 P_MSG_FLAG(CONFIRM);
712 P_MSG_FLAG(RST);
713 P_MSG_FLAG(ERRQUEUE);
714 P_MSG_FLAG(NOSIGNAL);
715 P_MSG_FLAG(MORE);
716 P_MSG_FLAG(WAITFORONE);
717 P_MSG_FLAG(SENDPAGE_NOTLAST);
718 P_MSG_FLAG(FASTOPEN);
719 P_MSG_FLAG(CMSG_CLOEXEC);
720#undef P_MSG_FLAG
721
722 if (flags)
723 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
724
725 return printed;
726}
727
728#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
729
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300730static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
731 struct syscall_arg *arg)
732{
733 size_t printed = 0;
734 int mode = arg->val;
735
736 if (mode == F_OK) /* 0 */
737 return scnprintf(bf, size, "F");
738#define P_MODE(n) \
739 if (mode & n##_OK) { \
740 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
741 mode &= ~n##_OK; \
742 }
743
744 P_MODE(R);
745 P_MODE(W);
746 P_MODE(X);
747#undef P_MODE
748
749 if (mode)
750 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
751
752 return printed;
753}
754
755#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
756
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300757static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
758 struct syscall_arg *arg);
759
760#define SCA_FILENAME syscall_arg__scnprintf_filename
761
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300762static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300763 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300764{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300765 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300766
767 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300768 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300769
770 if (flags == 0)
771 return scnprintf(bf, size, "RDONLY");
772#define P_FLAG(n) \
773 if (flags & O_##n) { \
774 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
775 flags &= ~O_##n; \
776 }
777
778 P_FLAG(APPEND);
779 P_FLAG(ASYNC);
780 P_FLAG(CLOEXEC);
781 P_FLAG(CREAT);
782 P_FLAG(DIRECT);
783 P_FLAG(DIRECTORY);
784 P_FLAG(EXCL);
785 P_FLAG(LARGEFILE);
786 P_FLAG(NOATIME);
787 P_FLAG(NOCTTY);
788#ifdef O_NONBLOCK
789 P_FLAG(NONBLOCK);
790#elif O_NDELAY
791 P_FLAG(NDELAY);
792#endif
793#ifdef O_PATH
794 P_FLAG(PATH);
795#endif
796 P_FLAG(RDWR);
797#ifdef O_DSYNC
798 if ((flags & O_SYNC) == O_SYNC)
799 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
800 else {
801 P_FLAG(DSYNC);
802 }
803#else
804 P_FLAG(SYNC);
805#endif
806 P_FLAG(TRUNC);
807 P_FLAG(WRONLY);
808#undef P_FLAG
809
810 if (flags)
811 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
812
813 return printed;
814}
815
816#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
817
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300818static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size,
819 struct syscall_arg *arg)
820{
821 int printed = 0, flags = arg->val;
822
823 if (flags == 0)
824 return 0;
825
826#define P_FLAG(n) \
827 if (flags & PERF_FLAG_##n) { \
828 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
829 flags &= ~PERF_FLAG_##n; \
830 }
831
832 P_FLAG(FD_NO_GROUP);
833 P_FLAG(FD_OUTPUT);
834 P_FLAG(PID_CGROUP);
835 P_FLAG(FD_CLOEXEC);
836#undef P_FLAG
837
838 if (flags)
839 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
840
841 return printed;
842}
843
844#define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags
845
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300846static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
847 struct syscall_arg *arg)
848{
849 int printed = 0, flags = arg->val;
850
851 if (flags == 0)
852 return scnprintf(bf, size, "NONE");
853#define P_FLAG(n) \
854 if (flags & EFD_##n) { \
855 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
856 flags &= ~EFD_##n; \
857 }
858
859 P_FLAG(SEMAPHORE);
860 P_FLAG(CLOEXEC);
861 P_FLAG(NONBLOCK);
862#undef P_FLAG
863
864 if (flags)
865 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
866
867 return printed;
868}
869
870#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
871
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300872static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
873 struct syscall_arg *arg)
874{
875 int printed = 0, flags = arg->val;
876
877#define P_FLAG(n) \
878 if (flags & O_##n) { \
879 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
880 flags &= ~O_##n; \
881 }
882
883 P_FLAG(CLOEXEC);
884 P_FLAG(NONBLOCK);
885#undef P_FLAG
886
887 if (flags)
888 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
889
890 return printed;
891}
892
893#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
894
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300895static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
896{
897 int sig = arg->val;
898
899 switch (sig) {
900#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
901 P_SIGNUM(HUP);
902 P_SIGNUM(INT);
903 P_SIGNUM(QUIT);
904 P_SIGNUM(ILL);
905 P_SIGNUM(TRAP);
906 P_SIGNUM(ABRT);
907 P_SIGNUM(BUS);
908 P_SIGNUM(FPE);
909 P_SIGNUM(KILL);
910 P_SIGNUM(USR1);
911 P_SIGNUM(SEGV);
912 P_SIGNUM(USR2);
913 P_SIGNUM(PIPE);
914 P_SIGNUM(ALRM);
915 P_SIGNUM(TERM);
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300916 P_SIGNUM(CHLD);
917 P_SIGNUM(CONT);
918 P_SIGNUM(STOP);
919 P_SIGNUM(TSTP);
920 P_SIGNUM(TTIN);
921 P_SIGNUM(TTOU);
922 P_SIGNUM(URG);
923 P_SIGNUM(XCPU);
924 P_SIGNUM(XFSZ);
925 P_SIGNUM(VTALRM);
926 P_SIGNUM(PROF);
927 P_SIGNUM(WINCH);
928 P_SIGNUM(IO);
929 P_SIGNUM(PWR);
930 P_SIGNUM(SYS);
Ben Hutchings02c5bb42014-02-06 01:00:41 +0000931#ifdef SIGEMT
932 P_SIGNUM(EMT);
933#endif
934#ifdef SIGSTKFLT
935 P_SIGNUM(STKFLT);
936#endif
937#ifdef SIGSWI
938 P_SIGNUM(SWI);
939#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300940 default: break;
941 }
942
943 return scnprintf(bf, size, "%#x", sig);
944}
945
946#define SCA_SIGNUM syscall_arg__scnprintf_signum
947
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300948#if defined(__i386__) || defined(__x86_64__)
949/*
950 * FIXME: Make this available to all arches.
951 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300952#define TCGETS 0x5401
953
954static const char *tioctls[] = {
955 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
956 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
957 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
958 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
959 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
960 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
961 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
962 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
963 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
964 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
965 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
966 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
967 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
968 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
969 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
970};
971
972static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300973#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300974
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300975#define STRARRAY(arg, name, array) \
976 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
977 .arg_parm = { [arg] = &strarray__##array, }
978
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300979static struct syscall_fmt {
980 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300981 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300982 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300983 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300984 bool errmsg;
985 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300986 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300987} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300988 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300989 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
990 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300991 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300992 { .name = "brk", .hexret = true,
993 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300994 { .name = "chdir", .errmsg = true,
995 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
996 { .name = "chmod", .errmsg = true,
997 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
998 { .name = "chroot", .errmsg = true,
999 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -06001000 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001001 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001002 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -03001003 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001004 { .name = "creat", .errmsg = true,
1005 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001006 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001007 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001008 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001009 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001010 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001011 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001012 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -03001013 { .name = "eventfd2", .errmsg = true,
1014 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001015 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001016 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1017 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001018 { .name = "fadvise64", .errmsg = true,
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 = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001021 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001022 { .name = "fchdir", .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 = "fchmod", .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 = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001027 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1028 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001029 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001030 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001031 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001032 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1033 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001034 { .name = "fcntl", .errmsg = true,
1035 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1036 [1] = SCA_STRARRAY, /* cmd */ },
1037 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1038 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001039 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -03001040 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001041 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1042 [1] = SCA_FLOCK, /* cmd */ }, },
1043 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001044 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001045 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001046 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001047 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001048 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1049 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001050 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001051 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001052 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001053 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001054 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001055 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -03001056 { .name = "futex", .errmsg = true,
1057 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001058 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001059 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1060 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001061 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001062 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001063 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001064 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001065 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1066 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001067 { .name = "getxattr", .errmsg = true,
1068 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1069 { .name = "inotify_add_watch", .errmsg = true,
1070 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001071 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001072 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001073#if defined(__i386__) || defined(__x86_64__)
1074/*
1075 * FIXME: Make this available to all arches.
1076 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001077 [1] = SCA_STRHEXARRAY, /* cmd */
1078 [2] = SCA_HEX, /* arg */ },
1079 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001080#else
1081 [2] = SCA_HEX, /* arg */ }, },
1082#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -03001083 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001084 { .name = "kill", .errmsg = true,
1085 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001086 { .name = "lchown", .errmsg = true,
1087 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1088 { .name = "lgetxattr", .errmsg = true,
1089 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001090 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001091 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001092 { .name = "listxattr", .errmsg = true,
1093 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001094 { .name = "llistxattr", .errmsg = true,
1095 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1096 { .name = "lremovexattr", .errmsg = true,
1097 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001098 { .name = "lseek", .errmsg = true,
1099 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1100 [2] = SCA_STRARRAY, /* whence */ },
1101 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001102 { .name = "lsetxattr", .errmsg = true,
1103 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001104 { .name = "lstat", .errmsg = true, .alias = "newlstat",
1105 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001106 { .name = "lsxattr", .errmsg = true,
1107 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001108 { .name = "madvise", .errmsg = true,
1109 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1110 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001111 { .name = "mkdir", .errmsg = true,
1112 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001113 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001114 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1115 [1] = SCA_FILENAME, /* pathname */ }, },
1116 { .name = "mknod", .errmsg = true,
1117 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001118 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001119 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1120 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001121 { .name = "mlock", .errmsg = true,
1122 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1123 { .name = "mlockall", .errmsg = true,
1124 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001125 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001126 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001127 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001128 [3] = SCA_MMAP_FLAGS, /* flags */
1129 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001130 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001131 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1132 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001133 { .name = "mq_unlink", .errmsg = true,
1134 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001135 { .name = "mremap", .hexret = true,
1136 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001137 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001138 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001139 { .name = "munlock", .errmsg = true,
1140 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001141 { .name = "munmap", .errmsg = true,
1142 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001143 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001144 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001145 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001146 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1147 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001148 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001149 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1150 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001151 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001152 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1153 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001154 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001155 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001156 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001157 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001158 { .name = "perf_event_open", .errmsg = true,
1159 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1160 [2] = SCA_INT, /* cpu */
1161 [3] = SCA_FD, /* group_fd */
1162 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001163 { .name = "pipe2", .errmsg = true,
1164 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001165 { .name = "poll", .errmsg = true, .timeout = true, },
1166 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001167 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001168 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001169 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001170 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001171 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001172 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001173 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001174 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001175 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001176 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001177 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001178 { .name = "readlink", .errmsg = true,
1179 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001180 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001181 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1182 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001183 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001184 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001185 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001186 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1187 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001188 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001189 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1190 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001191 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001192 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1193 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001194 { .name = "removexattr", .errmsg = true,
1195 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001196 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001197 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001198 { .name = "rmdir", .errmsg = true,
1199 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001200 { .name = "rt_sigaction", .errmsg = true,
1201 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001202 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001203 { .name = "rt_sigqueueinfo", .errmsg = true,
1204 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1205 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1206 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001207 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001208 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001209 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1210 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001211 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001212 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1213 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001214 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001215 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1216 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001217 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1218 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001219 { .name = "setxattr", .errmsg = true,
1220 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001221 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001222 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001223 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001224 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1225 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001226 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001227 { .name = "socketpair", .errmsg = true,
1228 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1229 [1] = SCA_SK_TYPE, /* type */ },
1230 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001231 { .name = "stat", .errmsg = true, .alias = "newstat",
1232 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001233 { .name = "statfs", .errmsg = true,
1234 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1235 { .name = "swapoff", .errmsg = true,
1236 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1237 { .name = "swapon", .errmsg = true,
1238 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001239 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001240 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001241 { .name = "tgkill", .errmsg = true,
1242 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1243 { .name = "tkill", .errmsg = true,
1244 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001245 { .name = "truncate", .errmsg = true,
1246 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001247 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001248 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001249 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1250 [1] = SCA_FILENAME, /* pathname */ }, },
1251 { .name = "utime", .errmsg = true,
1252 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001253 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001254 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1255 [1] = SCA_FILENAME, /* filename */ }, },
1256 { .name = "utimes", .errmsg = true,
1257 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001258 { .name = "vmsplice", .errmsg = true,
1259 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001260 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001261 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001262 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001263 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001264};
1265
1266static int syscall_fmt__cmp(const void *name, const void *fmtp)
1267{
1268 const struct syscall_fmt *fmt = fmtp;
1269 return strcmp(name, fmt->name);
1270}
1271
1272static struct syscall_fmt *syscall_fmt__find(const char *name)
1273{
1274 const int nmemb = ARRAY_SIZE(syscall_fmts);
1275 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1276}
1277
1278struct syscall {
1279 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001280 int nr_args;
1281 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001282 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001283 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001284 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001285 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001286 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001287};
1288
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001289static size_t fprintf_duration(unsigned long t, FILE *fp)
1290{
1291 double duration = (double)t / NSEC_PER_MSEC;
1292 size_t printed = fprintf(fp, "(");
1293
1294 if (duration >= 1.0)
1295 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1296 else if (duration >= 0.01)
1297 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1298 else
1299 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001300 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001301}
1302
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001303/**
1304 * filename.ptr: The filename char pointer that will be vfs_getname'd
1305 * filename.entry_str_pos: Where to insert the string translated from
1306 * filename.ptr by the vfs_getname tracepoint/kprobe.
1307 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001308struct thread_trace {
1309 u64 entry_time;
1310 u64 exit_time;
1311 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001312 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001313 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001314 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001315 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001316 struct {
1317 unsigned long ptr;
1318 int entry_str_pos;
1319 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001320 struct {
1321 int max;
1322 char **table;
1323 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001324
1325 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001326};
1327
1328static struct thread_trace *thread_trace__new(void)
1329{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001330 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1331
1332 if (ttrace)
1333 ttrace->paths.max = -1;
1334
David Ahernbf2575c2013-10-08 21:26:53 -06001335 ttrace->syscall_stats = intlist__new(NULL);
1336
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001337 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001338}
1339
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001340static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001341{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001342 struct thread_trace *ttrace;
1343
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001344 if (thread == NULL)
1345 goto fail;
1346
Namhyung Kim89dceb22014-10-06 09:46:03 +09001347 if (thread__priv(thread) == NULL)
1348 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001349
Namhyung Kim89dceb22014-10-06 09:46:03 +09001350 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001351 goto fail;
1352
Namhyung Kim89dceb22014-10-06 09:46:03 +09001353 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001354 ++ttrace->nr_events;
1355
1356 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001357fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001358 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001359 "WARNING: not enough memory, dropping samples!\n");
1360 return NULL;
1361}
1362
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001363#define TRACE_PFMAJ (1 << 0)
1364#define TRACE_PFMIN (1 << 1)
1365
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001366static const size_t trace__entry_str_size = 2048;
1367
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001368struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001369 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001370 struct {
1371 int machine;
1372 int open_id;
1373 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001374 struct {
1375 int max;
1376 struct syscall *table;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001377 struct {
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001378 struct perf_evsel *sys_enter,
1379 *sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001380 } events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001381 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001382 struct record_opts opts;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001383 struct perf_evlist *evlist;
David Ahern8fb598e2013-09-28 13:13:00 -06001384 struct machine *host;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001385 struct thread *current;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001386 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001387 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001388 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001389 struct strlist *ev_qualifier;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001390 struct {
1391 size_t nr;
1392 int *entries;
1393 } ev_qualifier_ids;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001394 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -06001395 struct intlist *tid_list;
1396 struct intlist *pid_list;
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08001397 struct {
1398 size_t nr;
1399 pid_t *entries;
1400 } filter_pids;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001401 double duration_filter;
1402 double runtime_ms;
1403 struct {
1404 u64 vfs_getname,
1405 proc_getname;
1406 } stats;
1407 bool not_ev_qualifier;
1408 bool live;
1409 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001410 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001411 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001412 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001413 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001414 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001415 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001416 bool trace_syscalls;
Yunlong Songe366a6d2015-04-02 21:47:18 +08001417 bool force;
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03001418 bool vfs_getname;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001419 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001420};
1421
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001422static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001423{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001424 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001425
1426 if (fd > ttrace->paths.max) {
1427 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1428
1429 if (npath == NULL)
1430 return -1;
1431
1432 if (ttrace->paths.max != -1) {
1433 memset(npath + ttrace->paths.max + 1, 0,
1434 (fd - ttrace->paths.max) * sizeof(char *));
1435 } else {
1436 memset(npath, 0, (fd + 1) * sizeof(char *));
1437 }
1438
1439 ttrace->paths.table = npath;
1440 ttrace->paths.max = fd;
1441 }
1442
1443 ttrace->paths.table[fd] = strdup(pathname);
1444
1445 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1446}
1447
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001448static int thread__read_fd_path(struct thread *thread, int fd)
1449{
1450 char linkname[PATH_MAX], pathname[PATH_MAX];
1451 struct stat st;
1452 int ret;
1453
1454 if (thread->pid_ == thread->tid) {
1455 scnprintf(linkname, sizeof(linkname),
1456 "/proc/%d/fd/%d", thread->pid_, fd);
1457 } else {
1458 scnprintf(linkname, sizeof(linkname),
1459 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1460 }
1461
1462 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1463 return -1;
1464
1465 ret = readlink(linkname, pathname, sizeof(pathname));
1466
1467 if (ret < 0 || ret > st.st_size)
1468 return -1;
1469
1470 pathname[ret] = '\0';
1471 return trace__set_fd_pathname(thread, fd, pathname);
1472}
1473
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001474static const char *thread__fd_path(struct thread *thread, int fd,
1475 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001476{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001477 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001478
1479 if (ttrace == NULL)
1480 return NULL;
1481
1482 if (fd < 0)
1483 return NULL;
1484
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001485 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001486 if (!trace->live)
1487 return NULL;
1488 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001489 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001490 return NULL;
1491 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001492
1493 return ttrace->paths.table[fd];
1494}
1495
1496static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1497 struct syscall_arg *arg)
1498{
1499 int fd = arg->val;
1500 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001501 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001502
1503 if (path)
1504 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1505
1506 return printed;
1507}
1508
1509static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1510 struct syscall_arg *arg)
1511{
1512 int fd = arg->val;
1513 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001514 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001515
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001516 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1517 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001518
1519 return printed;
1520}
1521
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001522static void thread__set_filename_pos(struct thread *thread, const char *bf,
1523 unsigned long ptr)
1524{
1525 struct thread_trace *ttrace = thread__priv(thread);
1526
1527 ttrace->filename.ptr = ptr;
1528 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1529}
1530
1531static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1532 struct syscall_arg *arg)
1533{
1534 unsigned long ptr = arg->val;
1535
1536 if (!arg->trace->vfs_getname)
1537 return scnprintf(bf, size, "%#x", ptr);
1538
1539 thread__set_filename_pos(arg->thread, bf, ptr);
1540 return 0;
1541}
1542
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001543static bool trace__filter_duration(struct trace *trace, double t)
1544{
1545 return t < (trace->duration_filter * NSEC_PER_MSEC);
1546}
1547
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001548static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1549{
1550 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1551
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001552 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001553}
1554
Namhyung Kimf15eb532012-10-05 14:02:16 +09001555static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001556static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001557
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001558static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001559{
1560 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001561 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001562}
1563
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001564static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001565 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001566{
1567 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001568 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001569
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001570 if (trace->multiple_threads) {
1571 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001572 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001573 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001574 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001575
1576 return printed;
1577}
1578
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001579static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001580 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001581{
1582 int ret = 0;
1583
1584 switch (event->header.type) {
1585 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001586 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001587 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001588 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001589 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001590 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001591 break;
1592 }
1593
1594 return ret;
1595}
1596
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001597static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001598 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001599 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001600 struct machine *machine)
1601{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001602 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001603 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001604}
1605
1606static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1607{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001608 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001609
1610 if (err)
1611 return err;
1612
David Ahern8fb598e2013-09-28 13:13:00 -06001613 trace->host = machine__new_host();
1614 if (trace->host == NULL)
1615 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001616
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001617 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001618 return -errno;
1619
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001620 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001621 evlist->threads, trace__tool_process, false,
1622 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001623 if (err)
1624 symbol__exit();
1625
1626 return err;
1627}
1628
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001629static int syscall__set_arg_fmts(struct syscall *sc)
1630{
1631 struct format_field *field;
1632 int idx = 0;
1633
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001634 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001635 if (sc->arg_scnprintf == NULL)
1636 return -1;
1637
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001638 if (sc->fmt)
1639 sc->arg_parm = sc->fmt->arg_parm;
1640
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001641 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001642 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1643 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1644 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001645 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1646 ++idx;
1647 }
1648
1649 return 0;
1650}
1651
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001652static int trace__read_syscall_info(struct trace *trace, int id)
1653{
1654 char tp_name[128];
1655 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001656 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001657
1658 if (name == NULL)
1659 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001660
1661 if (id > trace->syscalls.max) {
1662 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1663
1664 if (nsyscalls == NULL)
1665 return -1;
1666
1667 if (trace->syscalls.max != -1) {
1668 memset(nsyscalls + trace->syscalls.max + 1, 0,
1669 (id - trace->syscalls.max) * sizeof(*sc));
1670 } else {
1671 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1672 }
1673
1674 trace->syscalls.table = nsyscalls;
1675 trace->syscalls.max = id;
1676 }
1677
1678 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001679 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001680
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001681 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001682
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001683 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001684 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001685
1686 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1687 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001688 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001689 }
1690
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001691 if (sc->tp_format == NULL)
1692 return -1;
1693
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001694 sc->args = sc->tp_format->format.fields;
1695 sc->nr_args = sc->tp_format->format.nr_fields;
1696 /* drop nr field - not relevant here; does not exist on older kernels */
1697 if (sc->args && strcmp(sc->args->name, "nr") == 0) {
1698 sc->args = sc->args->next;
1699 --sc->nr_args;
1700 }
1701
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001702 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1703
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001704 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001705}
1706
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001707static int trace__validate_ev_qualifier(struct trace *trace)
1708{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001709 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001710 struct str_node *pos;
1711
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001712 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1713 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1714 sizeof(trace->ev_qualifier_ids.entries[0]));
1715
1716 if (trace->ev_qualifier_ids.entries == NULL) {
1717 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1718 trace->output);
1719 err = -EINVAL;
1720 goto out;
1721 }
1722
1723 i = 0;
1724
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001725 strlist__for_each(pos, trace->ev_qualifier) {
1726 const char *sc = pos->s;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001727 int id = audit_name_to_syscall(sc, trace->audit.machine);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001728
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001729 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001730 if (err == 0) {
1731 fputs("Error:\tInvalid syscall ", trace->output);
1732 err = -EINVAL;
1733 } else {
1734 fputs(", ", trace->output);
1735 }
1736
1737 fputs(sc, trace->output);
1738 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001739
1740 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001741 }
1742
1743 if (err < 0) {
1744 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1745 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001746 zfree(&trace->ev_qualifier_ids.entries);
1747 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001748 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001749out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001750 return err;
1751}
1752
David Ahern55d43bc2015-02-19 15:00:22 -05001753/*
1754 * args is to be interpreted as a series of longs but we need to handle
1755 * 8-byte unaligned accesses. args points to raw_data within the event
1756 * and raw_data is guaranteed to be 8-byte unaligned because it is
1757 * preceded by raw_size which is a u32. So we need to copy args to a temp
1758 * variable to read it. Most notably this avoids extended load instructions
1759 * on unaligned addresses
1760 */
1761
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001762static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001763 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001764 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001765{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001766 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001767 unsigned char *p;
1768 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001769
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001770 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001771 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001772 u8 bit = 1;
1773 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001774 .idx = 0,
1775 .mask = 0,
1776 .trace = trace,
1777 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001778 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001779
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001780 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001781 field = field->next, ++arg.idx, bit <<= 1) {
1782 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001783 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001784
1785 /* special care for unaligned accesses */
1786 p = args + sizeof(unsigned long) * arg.idx;
1787 memcpy(&val, p, sizeof(val));
1788
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001789 /*
1790 * Suppress this argument if its value is zero and
1791 * and we don't have a string associated in an
1792 * strarray for it.
1793 */
David Ahern55d43bc2015-02-19 15:00:22 -05001794 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001795 !(sc->arg_scnprintf &&
1796 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1797 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001798 continue;
1799
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001800 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001801 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001802 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001803 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001804 if (sc->arg_parm)
1805 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001806 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1807 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001808 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001809 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001810 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001811 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001812 }
1813 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001814 int i = 0;
1815
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001816 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001817 /* special care for unaligned accesses */
1818 p = args + sizeof(unsigned long) * i;
1819 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001820 printed += scnprintf(bf + printed, size - printed,
1821 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001822 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001823 ++i;
1824 }
1825 }
1826
1827 return printed;
1828}
1829
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001830typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001831 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001832 struct perf_sample *sample);
1833
1834static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001835 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001836{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001837
1838 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001839
1840 /*
1841 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1842 * before that, leaving at a higher verbosity level till that is
1843 * explained. Reproduced with plain ftrace with:
1844 *
1845 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1846 * grep "NR -1 " /t/trace_pipe
1847 *
1848 * After generating some load on the machine.
1849 */
1850 if (verbose > 1) {
1851 static u64 n;
1852 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1853 id, perf_evsel__name(evsel), ++n);
1854 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001855 return NULL;
1856 }
1857
1858 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1859 trace__read_syscall_info(trace, id))
1860 goto out_cant_read;
1861
1862 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1863 goto out_cant_read;
1864
1865 return &trace->syscalls.table[id];
1866
1867out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001868 if (verbose) {
1869 fprintf(trace->output, "Problems reading syscall %d", id);
1870 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1871 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1872 fputs(" information\n", trace->output);
1873 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001874 return NULL;
1875}
1876
David Ahernbf2575c2013-10-08 21:26:53 -06001877static void thread__update_stats(struct thread_trace *ttrace,
1878 int id, struct perf_sample *sample)
1879{
1880 struct int_node *inode;
1881 struct stats *stats;
1882 u64 duration = 0;
1883
1884 inode = intlist__findnew(ttrace->syscall_stats, id);
1885 if (inode == NULL)
1886 return;
1887
1888 stats = inode->priv;
1889 if (stats == NULL) {
1890 stats = malloc(sizeof(struct stats));
1891 if (stats == NULL)
1892 return;
1893 init_stats(stats);
1894 inode->priv = stats;
1895 }
1896
1897 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1898 duration = sample->time - ttrace->entry_time;
1899
1900 update_stats(stats, duration);
1901}
1902
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001903static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1904{
1905 struct thread_trace *ttrace;
1906 u64 duration;
1907 size_t printed;
1908
1909 if (trace->current == NULL)
1910 return 0;
1911
1912 ttrace = thread__priv(trace->current);
1913
1914 if (!ttrace->entry_pending)
1915 return 0;
1916
1917 duration = sample->time - ttrace->entry_time;
1918
1919 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1920 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1921 ttrace->entry_pending = false;
1922
1923 return printed;
1924}
1925
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001926static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001927 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001928 struct perf_sample *sample)
1929{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001930 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001931 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001932 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001933 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001934 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001935 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001936 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001937
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001938 if (sc == NULL)
1939 return -1;
1940
David Ahern8fb598e2013-09-28 13:13:00 -06001941 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001942 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001943 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001944 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001945
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001946 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001947
1948 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001949 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001950 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001951 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001952 }
1953
David Ahern13f22a22015-03-19 12:23:03 -06001954 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001955 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001956
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001957 ttrace->entry_time = sample->time;
1958 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001959 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001960
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001961 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001962 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001963
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001964 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001965 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001966 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1967 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001968 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001969 } else
1970 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001971
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001972 if (trace->current != thread) {
1973 thread__put(trace->current);
1974 trace->current = thread__get(thread);
1975 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001976 err = 0;
1977out_put:
1978 thread__put(thread);
1979 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001980}
1981
1982static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001983 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001984 struct perf_sample *sample)
1985{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001986 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001987 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001988 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001989 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001990 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001991 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001992
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001993 if (sc == NULL)
1994 return -1;
1995
David Ahern8fb598e2013-09-28 13:13:00 -06001996 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001997 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001998 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001999 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002000
David Ahernbf2575c2013-10-08 21:26:53 -06002001 if (trace->summary)
2002 thread__update_stats(ttrace, id, sample);
2003
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002004 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002005
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002006 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
2007 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
2008 trace->last_vfs_getname = NULL;
2009 ++trace->stats.vfs_getname;
2010 }
2011
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002012 ttrace->exit_time = sample->time;
2013
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002014 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002015 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002016 if (trace__filter_duration(trace, duration))
2017 goto out;
2018 } else if (trace->duration_filter)
2019 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002020
David Ahernfd2eaba2013-11-12 09:31:15 -07002021 if (trace->summary_only)
2022 goto out;
2023
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002024 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002025
2026 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002027 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002028 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002029 fprintf(trace->output, " ... [");
2030 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
2031 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002032 }
2033
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002034 if (sc->fmt == NULL) {
2035signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002036 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002037 } else if (ret < 0 && sc->fmt->errmsg) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00002038 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002039 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
2040 *e = audit_errno_to_name(-ret);
2041
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002042 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002043 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002044 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03002045 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002046 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002047 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002048 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002049
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002050 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002051out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002052 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002053 err = 0;
2054out_put:
2055 thread__put(thread);
2056 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002057}
2058
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002059static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002060 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002061 struct perf_sample *sample)
2062{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002063 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2064 struct thread_trace *ttrace;
2065 size_t filename_len, entry_str_len, to_move;
2066 ssize_t remaining_space;
2067 char *pos;
2068 const char *filename;
2069
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002070 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002071
2072 if (!thread)
2073 goto out;
2074
2075 ttrace = thread__priv(thread);
2076 if (!ttrace)
2077 goto out;
2078
2079 if (!ttrace->filename.ptr)
2080 goto out;
2081
2082 entry_str_len = strlen(ttrace->entry_str);
2083 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2084 if (remaining_space <= 0)
2085 goto out;
2086
2087 filename = trace->last_vfs_getname;
2088 filename_len = strlen(filename);
2089 if (filename_len > (size_t)remaining_space) {
2090 filename += filename_len - remaining_space;
2091 filename_len = remaining_space;
2092 }
2093
2094 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2095 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2096 memmove(pos + filename_len, pos, to_move);
2097 memcpy(pos, filename, filename_len);
2098
2099 ttrace->filename.ptr = 0;
2100 ttrace->filename.entry_str_pos = 0;
2101out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002102 return 0;
2103}
2104
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002105static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002106 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002107 struct perf_sample *sample)
2108{
2109 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2110 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06002111 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03002112 sample->pid,
2113 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002114 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002115
2116 if (ttrace == NULL)
2117 goto out_dump;
2118
2119 ttrace->runtime_ms += runtime_ms;
2120 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002121 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002122 return 0;
2123
2124out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002125 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002126 evsel->name,
2127 perf_evsel__strval(evsel, sample, "comm"),
2128 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2129 runtime,
2130 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002131 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002132 return 0;
2133}
2134
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002135static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2136 union perf_event *event __maybe_unused,
2137 struct perf_sample *sample)
2138{
2139 trace__printf_interrupted_entry(trace, sample);
2140 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002141
2142 if (trace->trace_syscalls)
2143 fprintf(trace->output, "( ): ");
2144
2145 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002146
2147 if (evsel->tp_format) {
2148 event_format__fprintf(evsel->tp_format, sample->cpu,
2149 sample->raw_data, sample->raw_size,
2150 trace->output);
2151 }
2152
2153 fprintf(trace->output, ")\n");
2154 return 0;
2155}
2156
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002157static void print_location(FILE *f, struct perf_sample *sample,
2158 struct addr_location *al,
2159 bool print_dso, bool print_sym)
2160{
2161
2162 if ((verbose || print_dso) && al->map)
2163 fprintf(f, "%s@", al->map->dso->long_name);
2164
2165 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002166 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002167 al->addr - al->sym->start);
2168 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002169 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002170 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002171 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002172}
2173
2174static int trace__pgfault(struct trace *trace,
2175 struct perf_evsel *evsel,
2176 union perf_event *event,
2177 struct perf_sample *sample)
2178{
2179 struct thread *thread;
2180 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
2181 struct addr_location al;
2182 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002183 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002184 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002185
2186 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002187 ttrace = thread__trace(thread, trace->output);
2188 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002189 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002190
2191 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2192 ttrace->pfmaj++;
2193 else
2194 ttrace->pfmin++;
2195
2196 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002197 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002198
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002199 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002200 sample->ip, &al);
2201
2202 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2203
2204 fprintf(trace->output, "%sfault [",
2205 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2206 "maj" : "min");
2207
2208 print_location(trace->output, sample, &al, false, true);
2209
2210 fprintf(trace->output, "] => ");
2211
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002212 thread__find_addr_location(thread, cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002213 sample->addr, &al);
2214
2215 if (!al.map) {
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002216 thread__find_addr_location(thread, cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002217 MAP__FUNCTION, sample->addr, &al);
2218
2219 if (al.map)
2220 map_type = 'x';
2221 else
2222 map_type = '?';
2223 }
2224
2225 print_location(trace->output, sample, &al, true, false);
2226
2227 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002228out:
2229 err = 0;
2230out_put:
2231 thread__put(thread);
2232 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002233}
2234
David Ahernbdc89662013-08-28 22:29:53 -06002235static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2236{
2237 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2238 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2239 return false;
2240
2241 if (trace->pid_list || trace->tid_list)
2242 return true;
2243
2244 return false;
2245}
2246
David Ahern6810fc92013-08-28 22:29:52 -06002247static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002248 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002249 struct perf_sample *sample,
2250 struct perf_evsel *evsel,
2251 struct machine *machine __maybe_unused)
2252{
2253 struct trace *trace = container_of(tool, struct trace, tool);
2254 int err = 0;
2255
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002256 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002257
David Ahernbdc89662013-08-28 22:29:53 -06002258 if (skip_sample(trace, sample))
2259 return 0;
2260
David Ahern4bb09192013-09-04 12:37:43 -06002261 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06002262 trace->base_time = sample->time;
2263
David Ahern31605652013-12-04 19:41:41 -07002264 if (handler) {
2265 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002266 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002267 }
David Ahern6810fc92013-08-28 22:29:52 -06002268
2269 return err;
2270}
2271
David Ahernbdc89662013-08-28 22:29:53 -06002272static int parse_target_str(struct trace *trace)
2273{
2274 if (trace->opts.target.pid) {
2275 trace->pid_list = intlist__new(trace->opts.target.pid);
2276 if (trace->pid_list == NULL) {
2277 pr_err("Error parsing process id string\n");
2278 return -EINVAL;
2279 }
2280 }
2281
2282 if (trace->opts.target.tid) {
2283 trace->tid_list = intlist__new(trace->opts.target.tid);
2284 if (trace->tid_list == NULL) {
2285 pr_err("Error parsing thread id string\n");
2286 return -EINVAL;
2287 }
2288 }
2289
2290 return 0;
2291}
2292
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002293static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002294{
2295 unsigned int rec_argc, i, j;
2296 const char **rec_argv;
2297 const char * const record_args[] = {
2298 "record",
2299 "-R",
2300 "-m", "1024",
2301 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002302 };
2303
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002304 const char * const sc_args[] = { "-e", };
2305 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2306 const char * const majpf_args[] = { "-e", "major-faults" };
2307 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2308 const char * const minpf_args[] = { "-e", "minor-faults" };
2309 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2310
David Ahern9aca7f12013-12-04 19:41:39 -07002311 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002312 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2313 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002314 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2315
2316 if (rec_argv == NULL)
2317 return -ENOMEM;
2318
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002319 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002320 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002321 rec_argv[j++] = record_args[i];
2322
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002323 if (trace->trace_syscalls) {
2324 for (i = 0; i < sc_args_nr; i++)
2325 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002326
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002327 /* event string may be different for older kernels - e.g., RHEL6 */
2328 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2329 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2330 else if (is_valid_tracepoint("syscalls:sys_enter"))
2331 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2332 else {
2333 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2334 return -1;
2335 }
David Ahern9aca7f12013-12-04 19:41:39 -07002336 }
David Ahern9aca7f12013-12-04 19:41:39 -07002337
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002338 if (trace->trace_pgfaults & TRACE_PFMAJ)
2339 for (i = 0; i < majpf_args_nr; i++)
2340 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002341
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002342 if (trace->trace_pgfaults & TRACE_PFMIN)
2343 for (i = 0; i < minpf_args_nr; i++)
2344 rec_argv[j++] = minpf_args[i];
2345
2346 for (i = 0; i < (unsigned int)argc; i++)
2347 rec_argv[j++] = argv[i];
2348
2349 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002350}
2351
David Ahernbf2575c2013-10-08 21:26:53 -06002352static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2353
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002354static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002355{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002356 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002357 if (evsel == NULL)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002358 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002359
2360 if (perf_evsel__field(evsel, "pathname") == NULL) {
2361 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002362 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002363 }
2364
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002365 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002366 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002367 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002368}
2369
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002370static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2371 u64 config)
2372{
2373 struct perf_evsel *evsel;
2374 struct perf_event_attr attr = {
2375 .type = PERF_TYPE_SOFTWARE,
2376 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002377 };
2378
2379 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002380 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002381
2382 event_attr_init(&attr);
2383
2384 evsel = perf_evsel__new(&attr);
2385 if (!evsel)
2386 return -ENOMEM;
2387
2388 evsel->handler = trace__pgfault;
2389 perf_evlist__add(evlist, evsel);
2390
2391 return 0;
2392}
2393
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002394static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2395{
2396 const u32 type = event->header.type;
2397 struct perf_evsel *evsel;
2398
2399 if (!trace->full_time && trace->base_time == 0)
2400 trace->base_time = sample->time;
2401
2402 if (type != PERF_RECORD_SAMPLE) {
2403 trace__process_event(trace, trace->host, event, sample);
2404 return;
2405 }
2406
2407 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2408 if (evsel == NULL) {
2409 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2410 return;
2411 }
2412
2413 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2414 sample->raw_data == NULL) {
2415 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2416 perf_evsel__name(evsel), sample->tid,
2417 sample->cpu, sample->raw_size);
2418 } else {
2419 tracepoint_handler handler = evsel->handler;
2420 handler(trace, evsel, event, sample);
2421 }
2422}
2423
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002424static int trace__add_syscall_newtp(struct trace *trace)
2425{
2426 int ret = -1;
2427 struct perf_evlist *evlist = trace->evlist;
2428 struct perf_evsel *sys_enter, *sys_exit;
2429
2430 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2431 if (sys_enter == NULL)
2432 goto out;
2433
2434 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2435 goto out_delete_sys_enter;
2436
2437 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2438 if (sys_exit == NULL)
2439 goto out_delete_sys_enter;
2440
2441 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2442 goto out_delete_sys_exit;
2443
2444 perf_evlist__add(evlist, sys_enter);
2445 perf_evlist__add(evlist, sys_exit);
2446
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002447 trace->syscalls.events.sys_enter = sys_enter;
2448 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002449
2450 ret = 0;
2451out:
2452 return ret;
2453
2454out_delete_sys_exit:
2455 perf_evsel__delete_priv(sys_exit);
2456out_delete_sys_enter:
2457 perf_evsel__delete_priv(sys_enter);
2458 goto out;
2459}
2460
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002461static int trace__set_ev_qualifier_filter(struct trace *trace)
2462{
2463 int err = -1;
2464 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2465 trace->ev_qualifier_ids.nr,
2466 trace->ev_qualifier_ids.entries);
2467
2468 if (filter == NULL)
2469 goto out_enomem;
2470
2471 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2472 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2473
2474 free(filter);
2475out:
2476 return err;
2477out_enomem:
2478 errno = ENOMEM;
2479 goto out;
2480}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002481
Namhyung Kimf15eb532012-10-05 14:02:16 +09002482static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002483{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002484 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002485 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002486 int err = -1, i;
2487 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002488 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002489 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002490
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002491 trace->live = true;
2492
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002493 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002494 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002495
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002496 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002497 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002498
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002499 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002500 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002501 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002502 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002503
2504 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2505 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002506 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002507
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002508 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002509 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2510 trace__sched_stat_runtime))
2511 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002512
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002513 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2514 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002515 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002516 goto out_delete_evlist;
2517 }
2518
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002519 err = trace__symbols_init(trace, evlist);
2520 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002521 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002522 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002523 }
2524
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002525 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002526
Namhyung Kimf15eb532012-10-05 14:02:16 +09002527 signal(SIGCHLD, sig_handler);
2528 signal(SIGINT, sig_handler);
2529
2530 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002531 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002532 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002533 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002534 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002535 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002536 }
2537 }
2538
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002539 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002540 if (err < 0)
2541 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002542
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002543 /*
2544 * Better not use !target__has_task() here because we need to cover the
2545 * case where no threads were specified in the command line, but a
2546 * workload was, and in that case we will fill in the thread_map when
2547 * we fork the workload in perf_evlist__prepare_workload.
2548 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002549 if (trace->filter_pids.nr > 0)
2550 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002551 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002552 err = perf_evlist__set_filter_pid(evlist, getpid());
2553
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002554 if (err < 0)
2555 goto out_error_mem;
2556
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002557 if (trace->ev_qualifier_ids.nr > 0) {
2558 err = trace__set_ev_qualifier_filter(trace);
2559 if (err < 0)
2560 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002561
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002562 pr_debug("event qualifier tracepoint filter: %s\n",
2563 trace->syscalls.events.sys_exit->filter);
2564 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002565
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002566 err = perf_evlist__apply_filters(evlist, &evsel);
2567 if (err < 0)
2568 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002569
Jiri Olsaf8850372013-11-28 17:57:22 +01002570 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002571 if (err < 0)
2572 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002573
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002574 if (!target__none(&trace->opts.target))
2575 perf_evlist__enable(evlist);
2576
Namhyung Kimf15eb532012-10-05 14:02:16 +09002577 if (forks)
2578 perf_evlist__start_workload(evlist);
2579
Jiri Olsae13798c2015-06-23 00:36:02 +02002580 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002581 evlist->threads->nr > 1 ||
2582 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002583again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002584 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002585
2586 for (i = 0; i < evlist->nr_mmaps; i++) {
2587 union perf_event *event;
2588
2589 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002590 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002591
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002592 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002593
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002594 err = perf_evlist__parse_sample(evlist, event, &sample);
2595 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002596 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002597 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002598 }
2599
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002600 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002601next_event:
2602 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002603
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002604 if (interrupted)
2605 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002606
2607 if (done && !draining) {
2608 perf_evlist__disable(evlist);
2609 draining = true;
2610 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002611 }
2612 }
2613
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002614 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002615 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002616
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002617 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2618 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2619 draining = true;
2620
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002621 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002622 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002623 } else {
2624 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002625 }
2626
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002627out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002628 thread__zput(trace->current);
2629
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002630 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002631
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002632 if (!err) {
2633 if (trace->summary)
2634 trace__fprintf_thread_summary(trace, trace->output);
2635
2636 if (trace->show_tool_stats) {
2637 fprintf(trace->output, "Stats:\n "
2638 " vfs_getname : %" PRIu64 "\n"
2639 " proc_getname: %" PRIu64 "\n",
2640 trace->stats.vfs_getname,
2641 trace->stats.proc_getname);
2642 }
2643 }
David Ahernbf2575c2013-10-08 21:26:53 -06002644
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002645out_delete_evlist:
2646 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002647 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002648 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002649 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002650{
2651 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002652
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002653out_error_sched_stat_runtime:
2654 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
2655 goto out_error;
2656
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002657out_error_raw_syscalls:
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002658 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002659 goto out_error;
2660
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002661out_error_mmap:
2662 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2663 goto out_error;
2664
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002665out_error_open:
2666 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2667
2668out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002669 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302670 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002671
2672out_error_apply_filters:
2673 fprintf(trace->output,
2674 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2675 evsel->filter, perf_evsel__name(evsel), errno,
2676 strerror_r(errno, errbuf, sizeof(errbuf)));
2677 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002678}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002679out_error_mem:
2680 fprintf(trace->output, "Not enough memory to run!\n");
2681 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002682
2683out_errno:
2684 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2685 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002686}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002687
David Ahern6810fc92013-08-28 22:29:52 -06002688static int trace__replay(struct trace *trace)
2689{
2690 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002691 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002692 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002693 struct perf_data_file file = {
2694 .path = input_name,
2695 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002696 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002697 };
David Ahern6810fc92013-08-28 22:29:52 -06002698 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002699 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002700 int err = -1;
2701
2702 trace->tool.sample = trace__process_sample;
2703 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002704 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002705 trace->tool.comm = perf_event__process_comm;
2706 trace->tool.exit = perf_event__process_exit;
2707 trace->tool.fork = perf_event__process_fork;
2708 trace->tool.attr = perf_event__process_attr;
2709 trace->tool.tracing_data = perf_event__process_tracing_data;
2710 trace->tool.build_id = perf_event__process_build_id;
2711
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002712 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002713 trace->tool.ordering_requires_timestamps = true;
2714
2715 /* add tid to output */
2716 trace->multiple_threads = true;
2717
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002718 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002719 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002720 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002721
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002722 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002723 goto out;
2724
David Ahern8fb598e2013-09-28 13:13:00 -06002725 trace->host = &session->machines.host;
2726
David Ahern6810fc92013-08-28 22:29:52 -06002727 err = perf_session__set_tracepoints_handlers(session, handlers);
2728 if (err)
2729 goto out;
2730
Namhyung Kim003824e2013-11-12 15:25:00 +09002731 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2732 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002733 /* older kernels have syscalls tp versus raw_syscalls */
2734 if (evsel == NULL)
2735 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2736 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002737
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002738 if (evsel &&
2739 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2740 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002741 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2742 goto out;
2743 }
2744
2745 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2746 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002747 if (evsel == NULL)
2748 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2749 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002750 if (evsel &&
2751 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2752 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002753 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002754 goto out;
2755 }
2756
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002757 evlist__for_each(session->evlist, evsel) {
2758 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2759 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2760 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2761 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2762 evsel->handler = trace__pgfault;
2763 }
2764
David Ahernbdc89662013-08-28 22:29:53 -06002765 err = parse_target_str(trace);
2766 if (err != 0)
2767 goto out;
2768
David Ahern6810fc92013-08-28 22:29:52 -06002769 setup_pager();
2770
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002771 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002772 if (err)
2773 pr_err("Failed to process events, error %d", err);
2774
David Ahernbf2575c2013-10-08 21:26:53 -06002775 else if (trace->summary)
2776 trace__fprintf_thread_summary(trace, trace->output);
2777
David Ahern6810fc92013-08-28 22:29:52 -06002778out:
2779 perf_session__delete(session);
2780
2781 return err;
2782}
2783
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002784static size_t trace__fprintf_threads_header(FILE *fp)
2785{
2786 size_t printed;
2787
Pekka Enberg99ff7152013-11-12 16:42:14 +02002788 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002789
2790 return printed;
2791}
2792
2793static size_t thread__dump_stats(struct thread_trace *ttrace,
2794 struct trace *trace, FILE *fp)
2795{
2796 struct stats *stats;
2797 size_t printed = 0;
2798 struct syscall *sc;
2799 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2800
2801 if (inode == NULL)
2802 return 0;
2803
2804 printed += fprintf(fp, "\n");
2805
Milian Wolff834fd462015-08-06 11:24:29 +02002806 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2807 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2808 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002809
David Ahernbf2575c2013-10-08 21:26:53 -06002810 /* each int_node is a syscall */
2811 while (inode) {
2812 stats = inode->priv;
2813 if (stats) {
2814 double min = (double)(stats->min) / NSEC_PER_MSEC;
2815 double max = (double)(stats->max) / NSEC_PER_MSEC;
2816 double avg = avg_stats(stats);
2817 double pct;
2818 u64 n = (u64) stats->n;
2819
2820 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2821 avg /= NSEC_PER_MSEC;
2822
2823 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002824 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002825 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
2826 n, avg * n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002827 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002828 }
2829
2830 inode = intlist__next(inode);
2831 }
2832
2833 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002834
2835 return printed;
2836}
2837
David Ahern896cbb52013-09-28 13:12:59 -06002838/* struct used to pass data to per-thread function */
2839struct summary_data {
2840 FILE *fp;
2841 struct trace *trace;
2842 size_t printed;
2843};
2844
2845static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2846{
2847 struct summary_data *data = priv;
2848 FILE *fp = data->fp;
2849 size_t printed = data->printed;
2850 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002851 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002852 double ratio;
2853
2854 if (ttrace == NULL)
2855 return 0;
2856
2857 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2858
Pekka Enberg15e65c62013-11-14 18:43:30 +02002859 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002860 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002861 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002862 if (ttrace->pfmaj)
2863 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2864 if (ttrace->pfmin)
2865 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002866 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002867 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002868
2869 data->printed += printed;
2870
2871 return 0;
2872}
2873
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002874static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2875{
David Ahern896cbb52013-09-28 13:12:59 -06002876 struct summary_data data = {
2877 .fp = fp,
2878 .trace = trace
2879 };
2880 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002881
David Ahern896cbb52013-09-28 13:12:59 -06002882 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002883
David Ahern896cbb52013-09-28 13:12:59 -06002884 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002885}
2886
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002887static int trace__set_duration(const struct option *opt, const char *str,
2888 int unset __maybe_unused)
2889{
2890 struct trace *trace = opt->value;
2891
2892 trace->duration_filter = atof(str);
2893 return 0;
2894}
2895
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002896static int trace__set_filter_pids(const struct option *opt, const char *str,
2897 int unset __maybe_unused)
2898{
2899 int ret = -1;
2900 size_t i;
2901 struct trace *trace = opt->value;
2902 /*
2903 * FIXME: introduce a intarray class, plain parse csv and create a
2904 * { int nr, int entries[] } struct...
2905 */
2906 struct intlist *list = intlist__new(str);
2907
2908 if (list == NULL)
2909 return -1;
2910
2911 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2912 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2913
2914 if (trace->filter_pids.entries == NULL)
2915 goto out;
2916
2917 trace->filter_pids.entries[0] = getpid();
2918
2919 for (i = 1; i < trace->filter_pids.nr; ++i)
2920 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2921
2922 intlist__delete(list);
2923 ret = 0;
2924out:
2925 return ret;
2926}
2927
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002928static int trace__open_output(struct trace *trace, const char *filename)
2929{
2930 struct stat st;
2931
2932 if (!stat(filename, &st) && st.st_size) {
2933 char oldname[PATH_MAX];
2934
2935 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2936 unlink(oldname);
2937 rename(filename, oldname);
2938 }
2939
2940 trace->output = fopen(filename, "w");
2941
2942 return trace->output == NULL ? -errno : 0;
2943}
2944
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002945static int parse_pagefaults(const struct option *opt, const char *str,
2946 int unset __maybe_unused)
2947{
2948 int *trace_pgfaults = opt->value;
2949
2950 if (strcmp(str, "all") == 0)
2951 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2952 else if (strcmp(str, "maj") == 0)
2953 *trace_pgfaults |= TRACE_PFMAJ;
2954 else if (strcmp(str, "min") == 0)
2955 *trace_pgfaults |= TRACE_PFMIN;
2956 else
2957 return -1;
2958
2959 return 0;
2960}
2961
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002962static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2963{
2964 struct perf_evsel *evsel;
2965
2966 evlist__for_each(evlist, evsel)
2967 evsel->handler = handler;
2968}
2969
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002970int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2971{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002972 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002973 "perf trace [<options>] [<command>]",
2974 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002975 "perf trace record [<options>] [<command>]",
2976 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002977 NULL
2978 };
2979 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002980 .audit = {
2981 .machine = audit_detect_machine(),
2982 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2983 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002984 .syscalls = {
2985 . max = -1,
2986 },
2987 .opts = {
2988 .target = {
2989 .uid = UINT_MAX,
2990 .uses_mmap = true,
2991 },
2992 .user_freq = UINT_MAX,
2993 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002994 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002995 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002996 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002997 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002998 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002999 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003000 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003001 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003002 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003003 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003004 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003005 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3006 "event selector. use 'perf list' to list available events",
3007 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003008 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3009 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003010 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03003011 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003012 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003013 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003014 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3015 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003016 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003017 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003018 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3019 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003020 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003021 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003022 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003023 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003024 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003025 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003026 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3027 "number of mmap data pages",
3028 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003029 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003030 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003031 OPT_CALLBACK(0, "duration", &trace, "float",
3032 "show only events with duration > N.M ms",
3033 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003034 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003035 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003036 OPT_BOOLEAN('T', "time", &trace.full_time,
3037 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003038 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3039 "Show only syscall summary with statistics"),
3040 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3041 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003042 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3043 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003044 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003045 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003046 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3047 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003048 OPT_END()
3049 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003050 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003051 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003052 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003053
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003054 signal(SIGSEGV, sighandler_dump_stack);
3055 signal(SIGFPE, sighandler_dump_stack);
3056
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003057 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003058
3059 if (trace.evlist == NULL) {
3060 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003061 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003062 goto out;
3063 }
3064
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003065 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3066 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003067
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003068 if (trace.trace_pgfaults) {
3069 trace.opts.sample_address = true;
3070 trace.opts.sample_time = true;
3071 }
3072
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003073 if (trace.evlist->nr_entries > 0)
3074 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3075
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003076 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3077 return trace__record(&trace, argc-1, &argv[1]);
3078
3079 /* summary_only implies summary option, but don't overwrite summary if set */
3080 if (trace.summary_only)
3081 trace.summary = trace.summary_only;
3082
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003083 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3084 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003085 pr_err("Please specify something to trace.\n");
3086 return -1;
3087 }
3088
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003089 if (output_name != NULL) {
3090 err = trace__open_output(&trace, output_name);
3091 if (err < 0) {
3092 perror("failed to create output file");
3093 goto out;
3094 }
3095 }
3096
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003097 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003098 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003099 struct strlist_config slist_config = {
3100 .dirname = system_path(STRACE_GROUPS_DIR),
3101 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003102
3103 trace.not_ev_qualifier = *s == '!';
3104 if (trace.not_ev_qualifier)
3105 ++s;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003106 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003107 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003108 fputs("Not enough memory to parse event qualifier",
3109 trace.output);
3110 err = -ENOMEM;
3111 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003112 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003113
3114 err = trace__validate_ev_qualifier(&trace);
3115 if (err)
3116 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003117 }
3118
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003119 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003120 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003121 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003122 fprintf(trace.output, "%s", bf);
3123 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003124 }
3125
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003126 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003127 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003128 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003129 fprintf(trace.output, "%s", bf);
3130 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003131 }
3132
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003133 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003134 trace.opts.target.system_wide = true;
3135
David Ahern6810fc92013-08-28 22:29:52 -06003136 if (input_name)
3137 err = trace__replay(&trace);
3138 else
3139 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003140
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003141out_close:
3142 if (output_name != NULL)
3143 fclose(trace.output);
3144out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003145 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003146}