blob: 9d23edc06698558231a1da49c465cbf092bdc194 [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030022#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030023#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030024#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060025#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030026#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -060027#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030028#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060029#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030030#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060031#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030032#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060033#include "util/stat.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010034#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070035#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000036#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020037#include "callchain.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030038#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030039#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030040
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030041#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030042#include <stdlib.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030043#include <linux/futex.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020044#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030045#include <linux/seccomp.h>
46#include <linux/filter.h>
47#include <linux/audit.h>
48#include <sys/ptrace.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030049#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030050#include <linux/stringify.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030051
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030052#ifndef O_CLOEXEC
53# define O_CLOEXEC 02000000
54#endif
55
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030056struct trace {
57 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030058 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030059 struct {
60 int max;
61 struct syscall *table;
62 struct {
63 struct perf_evsel *sys_enter,
64 *sys_exit;
65 } events;
66 } syscalls;
67 struct record_opts opts;
68 struct perf_evlist *evlist;
69 struct machine *host;
70 struct thread *current;
71 u64 base_time;
72 FILE *output;
73 unsigned long nr_events;
74 struct strlist *ev_qualifier;
75 struct {
76 size_t nr;
77 int *entries;
78 } ev_qualifier_ids;
79 struct intlist *tid_list;
80 struct intlist *pid_list;
81 struct {
82 size_t nr;
83 pid_t *entries;
84 } filter_pids;
85 double duration_filter;
86 double runtime_ms;
87 struct {
88 u64 vfs_getname,
89 proc_getname;
90 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030091 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -030092 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030093 bool not_ev_qualifier;
94 bool live;
95 bool full_time;
96 bool sched;
97 bool multiple_threads;
98 bool summary;
99 bool summary_only;
100 bool show_comm;
101 bool show_tool_stats;
102 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300103 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300104 bool force;
105 bool vfs_getname;
106 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300107 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300108};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300109
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300110struct tp_field {
111 int offset;
112 union {
113 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
114 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
115 };
116};
117
118#define TP_UINT_FIELD(bits) \
119static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
120{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500121 u##bits value; \
122 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
123 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300124}
125
126TP_UINT_FIELD(8);
127TP_UINT_FIELD(16);
128TP_UINT_FIELD(32);
129TP_UINT_FIELD(64);
130
131#define TP_UINT_FIELD__SWAPPED(bits) \
132static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
133{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500134 u##bits value; \
135 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300136 return bswap_##bits(value);\
137}
138
139TP_UINT_FIELD__SWAPPED(16);
140TP_UINT_FIELD__SWAPPED(32);
141TP_UINT_FIELD__SWAPPED(64);
142
143static int tp_field__init_uint(struct tp_field *field,
144 struct format_field *format_field,
145 bool needs_swap)
146{
147 field->offset = format_field->offset;
148
149 switch (format_field->size) {
150 case 1:
151 field->integer = tp_field__u8;
152 break;
153 case 2:
154 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
155 break;
156 case 4:
157 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
158 break;
159 case 8:
160 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
161 break;
162 default:
163 return -1;
164 }
165
166 return 0;
167}
168
169static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
170{
171 return sample->raw_data + field->offset;
172}
173
174static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
175{
176 field->offset = format_field->offset;
177 field->pointer = tp_field__ptr;
178 return 0;
179}
180
181struct syscall_tp {
182 struct tp_field id;
183 union {
184 struct tp_field args, ret;
185 };
186};
187
188static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
189 struct tp_field *field,
190 const char *name)
191{
192 struct format_field *format_field = perf_evsel__field(evsel, name);
193
194 if (format_field == NULL)
195 return -1;
196
197 return tp_field__init_uint(field, format_field, evsel->needs_swap);
198}
199
200#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
201 ({ struct syscall_tp *sc = evsel->priv;\
202 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
203
204static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
205 struct tp_field *field,
206 const char *name)
207{
208 struct format_field *format_field = perf_evsel__field(evsel, name);
209
210 if (format_field == NULL)
211 return -1;
212
213 return tp_field__init_ptr(field, format_field);
214}
215
216#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
217 ({ struct syscall_tp *sc = evsel->priv;\
218 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
219
220static void perf_evsel__delete_priv(struct perf_evsel *evsel)
221{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300222 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300223 perf_evsel__delete(evsel);
224}
225
Namhyung Kim96695d42013-11-12 08:51:45 -0300226static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
227{
228 evsel->priv = malloc(sizeof(struct syscall_tp));
229 if (evsel->priv != NULL) {
230 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
231 goto out_delete;
232
233 evsel->handler = handler;
234 return 0;
235 }
236
237 return -ENOMEM;
238
239out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300240 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300241 return -ENOENT;
242}
243
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300244static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300245{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300246 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300247
David Ahern9aca7f12013-12-04 19:41:39 -0700248 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200249 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700250 evsel = perf_evsel__newtp("syscalls", direction);
251
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200252 if (IS_ERR(evsel))
253 return NULL;
254
255 if (perf_evsel__init_syscall_tp(evsel, handler))
256 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300257
258 return evsel;
259
260out_delete:
261 perf_evsel__delete_priv(evsel);
262 return NULL;
263}
264
265#define perf_evsel__sc_tp_uint(evsel, name, sample) \
266 ({ struct syscall_tp *fields = evsel->priv; \
267 fields->name.integer(&fields->name, sample); })
268
269#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
270 ({ struct syscall_tp *fields = evsel->priv; \
271 fields->name.pointer(&fields->name, sample); })
272
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300273struct syscall_arg {
274 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300275 struct thread *thread;
276 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300277 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300278 u8 idx;
279 u8 mask;
280};
281
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300282struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300283 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300284 int nr_entries;
285 const char **entries;
286};
287
288#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
289 .nr_entries = ARRAY_SIZE(array), \
290 .entries = array, \
291}
292
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300293#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
294 .offset = off, \
295 .nr_entries = ARRAY_SIZE(array), \
296 .entries = array, \
297}
298
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300299static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
300 const char *intfmt,
301 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300302{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300303 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300304 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300305
306 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300307 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300308
309 return scnprintf(bf, size, "%s", sa->entries[idx]);
310}
311
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300312static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
313 struct syscall_arg *arg)
314{
315 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
316}
317
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300318#define SCA_STRARRAY syscall_arg__scnprintf_strarray
319
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300320#if defined(__i386__) || defined(__x86_64__)
321/*
322 * FIXME: Make this available to all arches as soon as the ioctl beautifier
323 * gets rewritten to support all arches.
324 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300325static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
326 struct syscall_arg *arg)
327{
328 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
329}
330
331#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300332#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300333
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300334static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
335 struct syscall_arg *arg);
336
337#define SCA_FD syscall_arg__scnprintf_fd
338
339static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
340 struct syscall_arg *arg)
341{
342 int fd = arg->val;
343
344 if (fd == AT_FDCWD)
345 return scnprintf(bf, size, "CWD");
346
347 return syscall_arg__scnprintf_fd(bf, size, arg);
348}
349
350#define SCA_FDAT syscall_arg__scnprintf_fd_at
351
352static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
353 struct syscall_arg *arg);
354
355#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
356
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300357static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300358 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300359{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300360 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300361}
362
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300363#define SCA_HEX syscall_arg__scnprintf_hex
364
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300365static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
366 struct syscall_arg *arg)
367{
368 return scnprintf(bf, size, "%d", arg->val);
369}
370
371#define SCA_INT syscall_arg__scnprintf_int
372
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300373static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
374 struct syscall_arg *arg)
375{
376 int printed = 0, op = arg->val;
377
378 if (op == 0)
379 return scnprintf(bf, size, "NONE");
380#define P_CMD(cmd) \
381 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
382 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
383 op &= ~LOCK_##cmd; \
384 }
385
386 P_CMD(SH);
387 P_CMD(EX);
388 P_CMD(NB);
389 P_CMD(UN);
390 P_CMD(MAND);
391 P_CMD(RW);
392 P_CMD(READ);
393 P_CMD(WRITE);
394#undef P_OP
395
396 if (op)
397 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
398
399 return printed;
400}
401
402#define SCA_FLOCK syscall_arg__scnprintf_flock
403
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300404static 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 -0300405{
406 enum syscall_futex_args {
407 SCF_UADDR = (1 << 0),
408 SCF_OP = (1 << 1),
409 SCF_VAL = (1 << 2),
410 SCF_TIMEOUT = (1 << 3),
411 SCF_UADDR2 = (1 << 4),
412 SCF_VAL3 = (1 << 5),
413 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300414 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300415 int cmd = op & FUTEX_CMD_MASK;
416 size_t printed = 0;
417
418 switch (cmd) {
419#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300420 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
421 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
422 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
423 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
424 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
425 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300426 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300427 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
428 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
429 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
430 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
431 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300432 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
433 default: printed = scnprintf(bf, size, "%#x", cmd); break;
434 }
435
436 if (op & FUTEX_PRIVATE_FLAG)
437 printed += scnprintf(bf + printed, size - printed, "|PRIV");
438
439 if (op & FUTEX_CLOCK_REALTIME)
440 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
441
442 return printed;
443}
444
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300445#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
446
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300447static const char *bpf_cmd[] = {
448 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
449 "MAP_GET_NEXT_KEY", "PROG_LOAD",
450};
451static DEFINE_STRARRAY(bpf_cmd);
452
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300453static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
454static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300455
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300456static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
457static DEFINE_STRARRAY(itimers);
458
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300459static const char *keyctl_options[] = {
460 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
461 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
462 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
463 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
464 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
465};
466static DEFINE_STRARRAY(keyctl_options);
467
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300468static const char *whences[] = { "SET", "CUR", "END",
469#ifdef SEEK_DATA
470"DATA",
471#endif
472#ifdef SEEK_HOLE
473"HOLE",
474#endif
475};
476static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300477
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300478static const char *fcntl_cmds[] = {
479 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
480 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
481 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
482 "F_GETOWNER_UIDS",
483};
484static DEFINE_STRARRAY(fcntl_cmds);
485
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300486static const char *rlimit_resources[] = {
487 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
488 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
489 "RTTIME",
490};
491static DEFINE_STRARRAY(rlimit_resources);
492
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300493static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
494static DEFINE_STRARRAY(sighow);
495
David Ahern4f8c1b72013-09-22 19:45:00 -0600496static const char *clockid[] = {
497 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300498 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
499 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600500};
501static DEFINE_STRARRAY(clockid);
502
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300503static const char *socket_families[] = {
504 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
505 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
506 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
507 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
508 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
509 "ALG", "NFC", "VSOCK",
510};
511static DEFINE_STRARRAY(socket_families);
512
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300513static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
514 struct syscall_arg *arg)
515{
516 size_t printed = 0;
517 int mode = arg->val;
518
519 if (mode == F_OK) /* 0 */
520 return scnprintf(bf, size, "F");
521#define P_MODE(n) \
522 if (mode & n##_OK) { \
523 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
524 mode &= ~n##_OK; \
525 }
526
527 P_MODE(R);
528 P_MODE(W);
529 P_MODE(X);
530#undef P_MODE
531
532 if (mode)
533 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
534
535 return printed;
536}
537
538#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
539
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300540static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
541 struct syscall_arg *arg);
542
543#define SCA_FILENAME syscall_arg__scnprintf_filename
544
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300545static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300546 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300547{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300548 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300549
550 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300551 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300552
553 if (flags == 0)
554 return scnprintf(bf, size, "RDONLY");
555#define P_FLAG(n) \
556 if (flags & O_##n) { \
557 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
558 flags &= ~O_##n; \
559 }
560
561 P_FLAG(APPEND);
562 P_FLAG(ASYNC);
563 P_FLAG(CLOEXEC);
564 P_FLAG(CREAT);
565 P_FLAG(DIRECT);
566 P_FLAG(DIRECTORY);
567 P_FLAG(EXCL);
568 P_FLAG(LARGEFILE);
569 P_FLAG(NOATIME);
570 P_FLAG(NOCTTY);
571#ifdef O_NONBLOCK
572 P_FLAG(NONBLOCK);
573#elif O_NDELAY
574 P_FLAG(NDELAY);
575#endif
576#ifdef O_PATH
577 P_FLAG(PATH);
578#endif
579 P_FLAG(RDWR);
580#ifdef O_DSYNC
581 if ((flags & O_SYNC) == O_SYNC)
582 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
583 else {
584 P_FLAG(DSYNC);
585 }
586#else
587 P_FLAG(SYNC);
588#endif
589 P_FLAG(TRUNC);
590 P_FLAG(WRONLY);
591#undef P_FLAG
592
593 if (flags)
594 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
595
596 return printed;
597}
598
599#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
600
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300601static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
602 struct syscall_arg *arg)
603{
604 int printed = 0, flags = arg->val;
605
606#define P_FLAG(n) \
607 if (flags & O_##n) { \
608 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
609 flags &= ~O_##n; \
610 }
611
612 P_FLAG(CLOEXEC);
613 P_FLAG(NONBLOCK);
614#undef P_FLAG
615
616 if (flags)
617 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
618
619 return printed;
620}
621
622#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
623
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300624static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
625{
626 int sig = arg->val;
627
628 switch (sig) {
629#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
630 P_SIGNUM(HUP);
631 P_SIGNUM(INT);
632 P_SIGNUM(QUIT);
633 P_SIGNUM(ILL);
634 P_SIGNUM(TRAP);
635 P_SIGNUM(ABRT);
636 P_SIGNUM(BUS);
637 P_SIGNUM(FPE);
638 P_SIGNUM(KILL);
639 P_SIGNUM(USR1);
640 P_SIGNUM(SEGV);
641 P_SIGNUM(USR2);
642 P_SIGNUM(PIPE);
643 P_SIGNUM(ALRM);
644 P_SIGNUM(TERM);
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300645 P_SIGNUM(CHLD);
646 P_SIGNUM(CONT);
647 P_SIGNUM(STOP);
648 P_SIGNUM(TSTP);
649 P_SIGNUM(TTIN);
650 P_SIGNUM(TTOU);
651 P_SIGNUM(URG);
652 P_SIGNUM(XCPU);
653 P_SIGNUM(XFSZ);
654 P_SIGNUM(VTALRM);
655 P_SIGNUM(PROF);
656 P_SIGNUM(WINCH);
657 P_SIGNUM(IO);
658 P_SIGNUM(PWR);
659 P_SIGNUM(SYS);
Ben Hutchings02c5bb42014-02-06 01:00:41 +0000660#ifdef SIGEMT
661 P_SIGNUM(EMT);
662#endif
663#ifdef SIGSTKFLT
664 P_SIGNUM(STKFLT);
665#endif
666#ifdef SIGSWI
667 P_SIGNUM(SWI);
668#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300669 default: break;
670 }
671
672 return scnprintf(bf, size, "%#x", sig);
673}
674
675#define SCA_SIGNUM syscall_arg__scnprintf_signum
676
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300677#if defined(__i386__) || defined(__x86_64__)
678/*
679 * FIXME: Make this available to all arches.
680 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300681#define TCGETS 0x5401
682
683static const char *tioctls[] = {
684 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
685 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
686 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
687 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
688 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
689 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
690 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
691 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
692 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
693 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
694 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
695 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
696 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
697 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
698 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
699};
700
701static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300702#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300703
Arnaldo Carvalho de Melo6fb35b92016-04-13 11:50:23 -0300704#ifndef SECCOMP_SET_MODE_STRICT
705#define SECCOMP_SET_MODE_STRICT 0
706#endif
707#ifndef SECCOMP_SET_MODE_FILTER
708#define SECCOMP_SET_MODE_FILTER 1
709#endif
710
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300711static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg)
712{
713 int op = arg->val;
714 size_t printed = 0;
715
716 switch (op) {
717#define P_SECCOMP_SET_MODE_OP(n) case SECCOMP_SET_MODE_##n: printed = scnprintf(bf, size, #n); break
718 P_SECCOMP_SET_MODE_OP(STRICT);
719 P_SECCOMP_SET_MODE_OP(FILTER);
720#undef P_SECCOMP_SET_MODE_OP
721 default: printed = scnprintf(bf, size, "%#x", op); break;
722 }
723
724 return printed;
725}
726
727#define SCA_SECCOMP_OP syscall_arg__scnprintf_seccomp_op
728
Arnaldo Carvalho de Melo6fb35b92016-04-13 11:50:23 -0300729#ifndef SECCOMP_FILTER_FLAG_TSYNC
730#define SECCOMP_FILTER_FLAG_TSYNC 1
731#endif
732
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300733static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size,
734 struct syscall_arg *arg)
735{
736 int printed = 0, flags = arg->val;
737
738#define P_FLAG(n) \
739 if (flags & SECCOMP_FILTER_FLAG_##n) { \
740 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
741 flags &= ~SECCOMP_FILTER_FLAG_##n; \
742 }
743
744 P_FLAG(TSYNC);
745#undef P_FLAG
746
747 if (flags)
748 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
749
750 return printed;
751}
752
753#define SCA_SECCOMP_FLAGS syscall_arg__scnprintf_seccomp_flags
754
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300755#ifndef GRND_NONBLOCK
756#define GRND_NONBLOCK 0x0001
757#endif
758#ifndef GRND_RANDOM
759#define GRND_RANDOM 0x0002
760#endif
761
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300762static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
763 struct syscall_arg *arg)
764{
765 int printed = 0, flags = arg->val;
766
767#define P_FLAG(n) \
768 if (flags & GRND_##n) { \
769 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
770 flags &= ~GRND_##n; \
771 }
772
773 P_FLAG(RANDOM);
774 P_FLAG(NONBLOCK);
775#undef P_FLAG
776
777 if (flags)
778 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
779
780 return printed;
781}
782
783#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
784
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300785#define STRARRAY(arg, name, array) \
786 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
787 .arg_parm = { [arg] = &strarray__##array, }
788
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300789#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300790#include "trace/beauty/pid.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300791#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300792#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300793#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300794#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300795#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300796#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300797#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300798
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300799static struct syscall_fmt {
800 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300801 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300802 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300803 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300804 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300805 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300806 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300807 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300808} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300809 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300810 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
811 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300812 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300813 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300814 { .name = "brk", .hexret = true,
815 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300816 { .name = "chdir", .errmsg = true,
817 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
818 { .name = "chmod", .errmsg = true,
819 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
820 { .name = "chroot", .errmsg = true,
821 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600822 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300823 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300824 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300825 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300826 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300827 { .name = "creat", .errmsg = true,
828 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300829 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300830 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300831 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300832 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300833 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300834 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300835 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300836 { .name = "eventfd2", .errmsg = true,
837 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300838 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300839 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
840 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300841 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300842 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300843 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300844 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300845 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300846 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300847 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300848 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300849 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300850 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
851 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300852 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300853 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300854 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300855 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
856 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300857 { .name = "fcntl", .errmsg = true,
858 .arg_scnprintf = { [0] = SCA_FD, /* fd */
859 [1] = SCA_STRARRAY, /* cmd */ },
860 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
861 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300862 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300863 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300864 .arg_scnprintf = { [0] = SCA_FD, /* fd */
865 [1] = SCA_FLOCK, /* cmd */ }, },
866 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300867 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300868 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300869 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300870 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300871 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
872 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300873 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300874 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300875 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300876 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300877 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300878 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300879 { .name = "futex", .errmsg = true,
880 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300881 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300882 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
883 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300884 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300885 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300886 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300887 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300888 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300889 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300890 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300891 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300892 { .name = "getrandom", .errmsg = true,
893 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300894 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300895 { .name = "getxattr", .errmsg = true,
896 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
897 { .name = "inotify_add_watch", .errmsg = true,
898 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300899 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300900 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300901#if defined(__i386__) || defined(__x86_64__)
902/*
903 * FIXME: Make this available to all arches.
904 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300905 [1] = SCA_STRHEXARRAY, /* cmd */
906 [2] = SCA_HEX, /* arg */ },
907 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300908#else
909 [2] = SCA_HEX, /* arg */ }, },
910#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300911 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300912 { .name = "kill", .errmsg = true,
913 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300914 { .name = "lchown", .errmsg = true,
915 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
916 { .name = "lgetxattr", .errmsg = true,
917 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300918 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300919 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300920 { .name = "listxattr", .errmsg = true,
921 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300922 { .name = "llistxattr", .errmsg = true,
923 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
924 { .name = "lremovexattr", .errmsg = true,
925 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300926 { .name = "lseek", .errmsg = true,
927 .arg_scnprintf = { [0] = SCA_FD, /* fd */
928 [2] = SCA_STRARRAY, /* whence */ },
929 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300930 { .name = "lsetxattr", .errmsg = true,
931 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300932 { .name = "lstat", .errmsg = true, .alias = "newlstat",
933 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300934 { .name = "lsxattr", .errmsg = true,
935 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300936 { .name = "madvise", .errmsg = true,
937 .arg_scnprintf = { [0] = SCA_HEX, /* start */
938 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300939 { .name = "mkdir", .errmsg = true,
940 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300941 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300942 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
943 [1] = SCA_FILENAME, /* pathname */ }, },
944 { .name = "mknod", .errmsg = true,
945 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300946 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300947 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
948 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300949 { .name = "mlock", .errmsg = true,
950 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
951 { .name = "mlockall", .errmsg = true,
952 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300953 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300954 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300955 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +0900956 [3] = SCA_MMAP_FLAGS, /* flags */
957 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300958 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300959 .arg_scnprintf = { [0] = SCA_HEX, /* start */
960 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300961 { .name = "mq_unlink", .errmsg = true,
962 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300963 { .name = "mremap", .hexret = true,
964 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +0300965 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300966 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300967 { .name = "munlock", .errmsg = true,
968 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300969 { .name = "munmap", .errmsg = true,
970 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300971 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300972 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300973 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300974 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
975 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300976 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300977 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
978 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300979 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300980 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
981 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300982 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300983 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300984 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300985 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300986 { .name = "perf_event_open", .errmsg = true,
Arnaldo Carvalho de Meloccd9b2a2016-04-26 11:40:17 -0300987 .arg_scnprintf = { [2] = SCA_INT, /* cpu */
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300988 [3] = SCA_FD, /* group_fd */
989 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300990 { .name = "pipe2", .errmsg = true,
991 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300992 { .name = "poll", .errmsg = true, .timeout = true, },
993 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300994 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300995 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300996 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300997 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300998 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300999 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001000 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001001 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001002 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001003 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001004 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001005 { .name = "readlink", .errmsg = true,
1006 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001007 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001008 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1009 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001010 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001011 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001012 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001013 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1014 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001015 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001016 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1017 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001018 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001019 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1020 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001021 { .name = "removexattr", .errmsg = true,
1022 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001023 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001024 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001025 { .name = "rmdir", .errmsg = true,
1026 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001027 { .name = "rt_sigaction", .errmsg = true,
1028 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001029 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001030 { .name = "rt_sigqueueinfo", .errmsg = true,
1031 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1032 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1033 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001034 { .name = "sched_setscheduler", .errmsg = true,
1035 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001036 { .name = "seccomp", .errmsg = true,
1037 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
1038 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001039 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001040 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001041 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1042 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001043 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001044 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1045 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001046 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001047 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1048 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001049 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001050 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001051 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001052 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001053 { .name = "setxattr", .errmsg = true,
1054 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001055 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001056 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001057 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001058 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1059 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001060 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001061 { .name = "socketpair", .errmsg = true,
1062 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1063 [1] = SCA_SK_TYPE, /* type */ },
1064 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001065 { .name = "stat", .errmsg = true, .alias = "newstat",
1066 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001067 { .name = "statfs", .errmsg = true,
1068 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1069 { .name = "swapoff", .errmsg = true,
1070 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1071 { .name = "swapon", .errmsg = true,
1072 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001073 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001074 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001075 { .name = "tgkill", .errmsg = true,
1076 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1077 { .name = "tkill", .errmsg = true,
1078 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001079 { .name = "truncate", .errmsg = true,
1080 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001081 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001082 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001083 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1084 [1] = SCA_FILENAME, /* pathname */ }, },
1085 { .name = "utime", .errmsg = true,
1086 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001087 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001088 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1089 [1] = SCA_FILENAME, /* filename */ }, },
1090 { .name = "utimes", .errmsg = true,
1091 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001092 { .name = "vmsplice", .errmsg = true,
1093 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001094 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001095 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001096 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001097 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001098 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001099 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001100 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001101 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001102};
1103
1104static int syscall_fmt__cmp(const void *name, const void *fmtp)
1105{
1106 const struct syscall_fmt *fmt = fmtp;
1107 return strcmp(name, fmt->name);
1108}
1109
1110static struct syscall_fmt *syscall_fmt__find(const char *name)
1111{
1112 const int nmemb = ARRAY_SIZE(syscall_fmts);
1113 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1114}
1115
1116struct syscall {
1117 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001118 int nr_args;
1119 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001120 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001121 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001122 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001123 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001124 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001125};
1126
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001127static size_t fprintf_duration(unsigned long t, FILE *fp)
1128{
1129 double duration = (double)t / NSEC_PER_MSEC;
1130 size_t printed = fprintf(fp, "(");
1131
1132 if (duration >= 1.0)
1133 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1134 else if (duration >= 0.01)
1135 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1136 else
1137 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001138 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001139}
1140
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001141/**
1142 * filename.ptr: The filename char pointer that will be vfs_getname'd
1143 * filename.entry_str_pos: Where to insert the string translated from
1144 * filename.ptr by the vfs_getname tracepoint/kprobe.
1145 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001146struct thread_trace {
1147 u64 entry_time;
1148 u64 exit_time;
1149 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001150 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001151 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001152 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001153 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001154 struct {
1155 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001156 short int entry_str_pos;
1157 bool pending_open;
1158 unsigned int namelen;
1159 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001160 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001161 struct {
1162 int max;
1163 char **table;
1164 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001165
1166 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001167};
1168
1169static struct thread_trace *thread_trace__new(void)
1170{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001171 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1172
1173 if (ttrace)
1174 ttrace->paths.max = -1;
1175
David Ahernbf2575c2013-10-08 21:26:53 -06001176 ttrace->syscall_stats = intlist__new(NULL);
1177
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001178 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001179}
1180
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001181static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001182{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001183 struct thread_trace *ttrace;
1184
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001185 if (thread == NULL)
1186 goto fail;
1187
Namhyung Kim89dceb22014-10-06 09:46:03 +09001188 if (thread__priv(thread) == NULL)
1189 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001190
Namhyung Kim89dceb22014-10-06 09:46:03 +09001191 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001192 goto fail;
1193
Namhyung Kim89dceb22014-10-06 09:46:03 +09001194 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001195 ++ttrace->nr_events;
1196
1197 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001198fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001199 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001200 "WARNING: not enough memory, dropping samples!\n");
1201 return NULL;
1202}
1203
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001204#define TRACE_PFMAJ (1 << 0)
1205#define TRACE_PFMIN (1 << 1)
1206
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001207static const size_t trace__entry_str_size = 2048;
1208
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001209static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001210{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001211 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001212
1213 if (fd > ttrace->paths.max) {
1214 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1215
1216 if (npath == NULL)
1217 return -1;
1218
1219 if (ttrace->paths.max != -1) {
1220 memset(npath + ttrace->paths.max + 1, 0,
1221 (fd - ttrace->paths.max) * sizeof(char *));
1222 } else {
1223 memset(npath, 0, (fd + 1) * sizeof(char *));
1224 }
1225
1226 ttrace->paths.table = npath;
1227 ttrace->paths.max = fd;
1228 }
1229
1230 ttrace->paths.table[fd] = strdup(pathname);
1231
1232 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1233}
1234
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001235static int thread__read_fd_path(struct thread *thread, int fd)
1236{
1237 char linkname[PATH_MAX], pathname[PATH_MAX];
1238 struct stat st;
1239 int ret;
1240
1241 if (thread->pid_ == thread->tid) {
1242 scnprintf(linkname, sizeof(linkname),
1243 "/proc/%d/fd/%d", thread->pid_, fd);
1244 } else {
1245 scnprintf(linkname, sizeof(linkname),
1246 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1247 }
1248
1249 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1250 return -1;
1251
1252 ret = readlink(linkname, pathname, sizeof(pathname));
1253
1254 if (ret < 0 || ret > st.st_size)
1255 return -1;
1256
1257 pathname[ret] = '\0';
1258 return trace__set_fd_pathname(thread, fd, pathname);
1259}
1260
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001261static const char *thread__fd_path(struct thread *thread, int fd,
1262 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001263{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001264 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001265
1266 if (ttrace == NULL)
1267 return NULL;
1268
1269 if (fd < 0)
1270 return NULL;
1271
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001272 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001273 if (!trace->live)
1274 return NULL;
1275 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001276 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001277 return NULL;
1278 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001279
1280 return ttrace->paths.table[fd];
1281}
1282
1283static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1284 struct syscall_arg *arg)
1285{
1286 int fd = arg->val;
1287 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001288 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001289
1290 if (path)
1291 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1292
1293 return printed;
1294}
1295
1296static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1297 struct syscall_arg *arg)
1298{
1299 int fd = arg->val;
1300 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001301 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001302
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001303 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1304 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001305
1306 return printed;
1307}
1308
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001309static void thread__set_filename_pos(struct thread *thread, const char *bf,
1310 unsigned long ptr)
1311{
1312 struct thread_trace *ttrace = thread__priv(thread);
1313
1314 ttrace->filename.ptr = ptr;
1315 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1316}
1317
1318static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1319 struct syscall_arg *arg)
1320{
1321 unsigned long ptr = arg->val;
1322
1323 if (!arg->trace->vfs_getname)
1324 return scnprintf(bf, size, "%#x", ptr);
1325
1326 thread__set_filename_pos(arg->thread, bf, ptr);
1327 return 0;
1328}
1329
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001330static bool trace__filter_duration(struct trace *trace, double t)
1331{
1332 return t < (trace->duration_filter * NSEC_PER_MSEC);
1333}
1334
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001335static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1336{
1337 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1338
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001339 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001340}
1341
Namhyung Kimf15eb532012-10-05 14:02:16 +09001342static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001343static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001344
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001345static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001346{
1347 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001348 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001349}
1350
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001351static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001352 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001353{
1354 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001355 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001356
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001357 if (trace->multiple_threads) {
1358 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001359 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001360 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001361 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001362
1363 return printed;
1364}
1365
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001366static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001367 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001368{
1369 int ret = 0;
1370
1371 switch (event->header.type) {
1372 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001373 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001374 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001375 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001376 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001377 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001378 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001379 break;
1380 }
1381
1382 return ret;
1383}
1384
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001385static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001386 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001387 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001388 struct machine *machine)
1389{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001390 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001391 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001392}
1393
1394static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1395{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001396 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001397
1398 if (err)
1399 return err;
1400
David Ahern8fb598e2013-09-28 13:13:00 -06001401 trace->host = machine__new_host();
1402 if (trace->host == NULL)
1403 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001404
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001405 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001406 return -errno;
1407
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001408 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001409 evlist->threads, trace__tool_process, false,
1410 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001411 if (err)
1412 symbol__exit();
1413
1414 return err;
1415}
1416
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001417static int syscall__set_arg_fmts(struct syscall *sc)
1418{
1419 struct format_field *field;
1420 int idx = 0;
1421
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001422 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001423 if (sc->arg_scnprintf == NULL)
1424 return -1;
1425
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001426 if (sc->fmt)
1427 sc->arg_parm = sc->fmt->arg_parm;
1428
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001429 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001430 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1431 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1432 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001433 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001434 else if (strcmp(field->type, "pid_t") == 0)
1435 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001436 else if (strcmp(field->type, "umode_t") == 0)
1437 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001438 ++idx;
1439 }
1440
1441 return 0;
1442}
1443
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001444static int trace__read_syscall_info(struct trace *trace, int id)
1445{
1446 char tp_name[128];
1447 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001448 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001449
1450 if (name == NULL)
1451 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001452
1453 if (id > trace->syscalls.max) {
1454 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1455
1456 if (nsyscalls == NULL)
1457 return -1;
1458
1459 if (trace->syscalls.max != -1) {
1460 memset(nsyscalls + trace->syscalls.max + 1, 0,
1461 (id - trace->syscalls.max) * sizeof(*sc));
1462 } else {
1463 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1464 }
1465
1466 trace->syscalls.table = nsyscalls;
1467 trace->syscalls.max = id;
1468 }
1469
1470 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001471 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001472
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001473 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001474
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001475 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001476 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001477
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001478 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001479 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001480 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001481 }
1482
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001483 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001484 return -1;
1485
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001486 sc->args = sc->tp_format->format.fields;
1487 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001488 /*
1489 * We need to check and discard the first variable '__syscall_nr'
1490 * or 'nr' that mean the syscall number. It is needless here.
1491 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1492 */
1493 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001494 sc->args = sc->args->next;
1495 --sc->nr_args;
1496 }
1497
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001498 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1499
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001500 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001501}
1502
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001503static int trace__validate_ev_qualifier(struct trace *trace)
1504{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001505 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001506 struct str_node *pos;
1507
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001508 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1509 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1510 sizeof(trace->ev_qualifier_ids.entries[0]));
1511
1512 if (trace->ev_qualifier_ids.entries == NULL) {
1513 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1514 trace->output);
1515 err = -EINVAL;
1516 goto out;
1517 }
1518
1519 i = 0;
1520
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001521 strlist__for_each(pos, trace->ev_qualifier) {
1522 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001523 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001524
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001525 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001526 if (err == 0) {
1527 fputs("Error:\tInvalid syscall ", trace->output);
1528 err = -EINVAL;
1529 } else {
1530 fputs(", ", trace->output);
1531 }
1532
1533 fputs(sc, trace->output);
1534 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001535
1536 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001537 }
1538
1539 if (err < 0) {
1540 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1541 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001542 zfree(&trace->ev_qualifier_ids.entries);
1543 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001544 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001545out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001546 return err;
1547}
1548
David Ahern55d43bca2015-02-19 15:00:22 -05001549/*
1550 * args is to be interpreted as a series of longs but we need to handle
1551 * 8-byte unaligned accesses. args points to raw_data within the event
1552 * and raw_data is guaranteed to be 8-byte unaligned because it is
1553 * preceded by raw_size which is a u32. So we need to copy args to a temp
1554 * variable to read it. Most notably this avoids extended load instructions
1555 * on unaligned addresses
1556 */
1557
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001558static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001559 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001560 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001561{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001562 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001563 unsigned char *p;
1564 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001565
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001566 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001567 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001568 u8 bit = 1;
1569 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001570 .idx = 0,
1571 .mask = 0,
1572 .trace = trace,
1573 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001574 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001575
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001576 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001577 field = field->next, ++arg.idx, bit <<= 1) {
1578 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001579 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001580
1581 /* special care for unaligned accesses */
1582 p = args + sizeof(unsigned long) * arg.idx;
1583 memcpy(&val, p, sizeof(val));
1584
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001585 /*
1586 * Suppress this argument if its value is zero and
1587 * and we don't have a string associated in an
1588 * strarray for it.
1589 */
David Ahern55d43bca2015-02-19 15:00:22 -05001590 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001591 !(sc->arg_scnprintf &&
1592 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1593 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001594 continue;
1595
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001596 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001597 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001598 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bca2015-02-19 15:00:22 -05001599 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001600 if (sc->arg_parm)
1601 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001602 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1603 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001604 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001605 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bca2015-02-19 15:00:22 -05001606 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001607 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001608 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001609 } else if (IS_ERR(sc->tp_format)) {
1610 /*
1611 * If we managed to read the tracepoint /format file, then we
1612 * may end up not having any args, like with gettid(), so only
1613 * print the raw args when we didn't manage to read it.
1614 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001615 int i = 0;
1616
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001617 while (i < 6) {
David Ahern55d43bca2015-02-19 15:00:22 -05001618 /* special care for unaligned accesses */
1619 p = args + sizeof(unsigned long) * i;
1620 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001621 printed += scnprintf(bf + printed, size - printed,
1622 "%sarg%d: %ld",
David Ahern55d43bca2015-02-19 15:00:22 -05001623 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001624 ++i;
1625 }
1626 }
1627
1628 return printed;
1629}
1630
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001631typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001632 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001633 struct perf_sample *sample);
1634
1635static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001636 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001637{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001638
1639 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001640
1641 /*
1642 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1643 * before that, leaving at a higher verbosity level till that is
1644 * explained. Reproduced with plain ftrace with:
1645 *
1646 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1647 * grep "NR -1 " /t/trace_pipe
1648 *
1649 * After generating some load on the machine.
1650 */
1651 if (verbose > 1) {
1652 static u64 n;
1653 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1654 id, perf_evsel__name(evsel), ++n);
1655 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001656 return NULL;
1657 }
1658
1659 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1660 trace__read_syscall_info(trace, id))
1661 goto out_cant_read;
1662
1663 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1664 goto out_cant_read;
1665
1666 return &trace->syscalls.table[id];
1667
1668out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001669 if (verbose) {
1670 fprintf(trace->output, "Problems reading syscall %d", id);
1671 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1672 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1673 fputs(" information\n", trace->output);
1674 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001675 return NULL;
1676}
1677
David Ahernbf2575c2013-10-08 21:26:53 -06001678static void thread__update_stats(struct thread_trace *ttrace,
1679 int id, struct perf_sample *sample)
1680{
1681 struct int_node *inode;
1682 struct stats *stats;
1683 u64 duration = 0;
1684
1685 inode = intlist__findnew(ttrace->syscall_stats, id);
1686 if (inode == NULL)
1687 return;
1688
1689 stats = inode->priv;
1690 if (stats == NULL) {
1691 stats = malloc(sizeof(struct stats));
1692 if (stats == NULL)
1693 return;
1694 init_stats(stats);
1695 inode->priv = stats;
1696 }
1697
1698 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1699 duration = sample->time - ttrace->entry_time;
1700
1701 update_stats(stats, duration);
1702}
1703
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001704static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1705{
1706 struct thread_trace *ttrace;
1707 u64 duration;
1708 size_t printed;
1709
1710 if (trace->current == NULL)
1711 return 0;
1712
1713 ttrace = thread__priv(trace->current);
1714
1715 if (!ttrace->entry_pending)
1716 return 0;
1717
1718 duration = sample->time - ttrace->entry_time;
1719
1720 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1721 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1722 ttrace->entry_pending = false;
1723
1724 return printed;
1725}
1726
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001727static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001728 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001729 struct perf_sample *sample)
1730{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001731 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001732 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001733 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001734 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001735 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001736 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001737 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001738
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001739 if (sc == NULL)
1740 return -1;
1741
David Ahern8fb598e2013-09-28 13:13:00 -06001742 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001743 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001744 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001745 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001746
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001747 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001748
1749 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001750 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001751 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001752 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001753 }
1754
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001755 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001756 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001757
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001758 ttrace->entry_time = sample->time;
1759 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001760 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001761
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001762 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001763 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001764
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001765 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001766 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001767 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1768 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001769 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001770 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001771 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001772 /* See trace__vfs_getname & trace__sys_exit */
1773 ttrace->filename.pending_open = false;
1774 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001775
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001776 if (trace->current != thread) {
1777 thread__put(trace->current);
1778 trace->current = thread__get(thread);
1779 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001780 err = 0;
1781out_put:
1782 thread__put(thread);
1783 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001784}
1785
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001786static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1787 struct perf_sample *sample,
1788 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001789{
1790 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001791
1792 if (machine__resolve(trace->host, &al, sample) < 0 ||
1793 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1794 return -1;
1795
1796 return 0;
1797}
1798
1799static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1800{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001801 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001802 const unsigned int print_opts = EVSEL__PRINT_SYM |
1803 EVSEL__PRINT_DSO |
1804 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001805
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001806 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001807}
1808
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001809static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001810 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001811 struct perf_sample *sample)
1812{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001813 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001814 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001815 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001816 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001817 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001818 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001819
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001820 if (sc == NULL)
1821 return -1;
1822
David Ahern8fb598e2013-09-28 13:13:00 -06001823 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001824 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001825 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001826 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001827
David Ahernbf2575c2013-10-08 21:26:53 -06001828 if (trace->summary)
1829 thread__update_stats(ttrace, id, sample);
1830
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001831 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001832
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001833 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001834 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1835 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001836 ++trace->stats.vfs_getname;
1837 }
1838
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001839 ttrace->exit_time = sample->time;
1840
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001841 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001842 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001843 if (trace__filter_duration(trace, duration))
1844 goto out;
1845 } else if (trace->duration_filter)
1846 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001847
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001848 if (sample->callchain) {
1849 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1850 if (callchain_ret == 0) {
1851 if (callchain_cursor.nr < trace->min_stack)
1852 goto out;
1853 callchain_ret = 1;
1854 }
1855 }
1856
David Ahernfd2eaba2013-11-12 09:31:15 -07001857 if (trace->summary_only)
1858 goto out;
1859
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001860 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001861
1862 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001863 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001864 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001865 fprintf(trace->output, " ... [");
1866 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1867 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001868 }
1869
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001870 if (sc->fmt == NULL) {
1871signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001872 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001873 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001874 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001875 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1876 *e = audit_errno_to_name(-ret);
1877
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001878 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001879 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001880 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001881 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001882 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001883 else if (sc->fmt->errpid) {
1884 struct thread *child = machine__find_thread(trace->host, ret, ret);
1885
1886 if (child != NULL) {
1887 fprintf(trace->output, ") = %ld", ret);
1888 if (child->comm_set)
1889 fprintf(trace->output, " (%s)", thread__comm_str(child));
1890 thread__put(child);
1891 }
1892 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001893 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001894
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001895 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001896
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001897 if (callchain_ret > 0)
1898 trace__fprintf_callchain(trace, sample);
1899 else if (callchain_ret < 0)
1900 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001901out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001902 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001903 err = 0;
1904out_put:
1905 thread__put(thread);
1906 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001907}
1908
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001909static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001910 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001911 struct perf_sample *sample)
1912{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001913 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1914 struct thread_trace *ttrace;
1915 size_t filename_len, entry_str_len, to_move;
1916 ssize_t remaining_space;
1917 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001918 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001919
1920 if (!thread)
1921 goto out;
1922
1923 ttrace = thread__priv(thread);
1924 if (!ttrace)
1925 goto out;
1926
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001927 filename_len = strlen(filename);
1928
1929 if (ttrace->filename.namelen < filename_len) {
1930 char *f = realloc(ttrace->filename.name, filename_len + 1);
1931
1932 if (f == NULL)
1933 goto out;
1934
1935 ttrace->filename.namelen = filename_len;
1936 ttrace->filename.name = f;
1937 }
1938
1939 strcpy(ttrace->filename.name, filename);
1940 ttrace->filename.pending_open = true;
1941
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001942 if (!ttrace->filename.ptr)
1943 goto out;
1944
1945 entry_str_len = strlen(ttrace->entry_str);
1946 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1947 if (remaining_space <= 0)
1948 goto out;
1949
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001950 if (filename_len > (size_t)remaining_space) {
1951 filename += filename_len - remaining_space;
1952 filename_len = remaining_space;
1953 }
1954
1955 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1956 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1957 memmove(pos + filename_len, pos, to_move);
1958 memcpy(pos, filename, filename_len);
1959
1960 ttrace->filename.ptr = 0;
1961 ttrace->filename.entry_str_pos = 0;
1962out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001963 return 0;
1964}
1965
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001966static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001967 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001968 struct perf_sample *sample)
1969{
1970 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1971 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001972 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001973 sample->pid,
1974 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001975 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001976
1977 if (ttrace == NULL)
1978 goto out_dump;
1979
1980 ttrace->runtime_ms += runtime_ms;
1981 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001982 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001983 return 0;
1984
1985out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001986 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001987 evsel->name,
1988 perf_evsel__strval(evsel, sample, "comm"),
1989 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1990 runtime,
1991 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001992 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001993 return 0;
1994}
1995
Wang Nan1d6c9402016-02-26 09:31:55 +00001996static void bpf_output__printer(enum binary_printer_ops op,
1997 unsigned int val, void *extra)
1998{
1999 FILE *output = extra;
2000 unsigned char ch = (unsigned char)val;
2001
2002 switch (op) {
2003 case BINARY_PRINT_CHAR_DATA:
2004 fprintf(output, "%c", isprint(ch) ? ch : '.');
2005 break;
2006 case BINARY_PRINT_DATA_BEGIN:
2007 case BINARY_PRINT_LINE_BEGIN:
2008 case BINARY_PRINT_ADDR:
2009 case BINARY_PRINT_NUM_DATA:
2010 case BINARY_PRINT_NUM_PAD:
2011 case BINARY_PRINT_SEP:
2012 case BINARY_PRINT_CHAR_PAD:
2013 case BINARY_PRINT_LINE_END:
2014 case BINARY_PRINT_DATA_END:
2015 default:
2016 break;
2017 }
2018}
2019
2020static void bpf_output__fprintf(struct trace *trace,
2021 struct perf_sample *sample)
2022{
2023 print_binary(sample->raw_data, sample->raw_size, 8,
2024 bpf_output__printer, trace->output);
2025}
2026
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002027static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2028 union perf_event *event __maybe_unused,
2029 struct perf_sample *sample)
2030{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002031 int callchain_ret = 0;
2032
2033 if (sample->callchain) {
2034 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2035 if (callchain_ret == 0) {
2036 if (callchain_cursor.nr < trace->min_stack)
2037 goto out;
2038 callchain_ret = 1;
2039 }
2040 }
2041
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002042 trace__printf_interrupted_entry(trace, sample);
2043 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002044
2045 if (trace->trace_syscalls)
2046 fprintf(trace->output, "( ): ");
2047
2048 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002049
Wang Nan1d6c9402016-02-26 09:31:55 +00002050 if (perf_evsel__is_bpf_output(evsel)) {
2051 bpf_output__fprintf(trace, sample);
2052 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002053 event_format__fprintf(evsel->tp_format, sample->cpu,
2054 sample->raw_data, sample->raw_size,
2055 trace->output);
2056 }
2057
2058 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03002059
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002060 if (callchain_ret > 0)
2061 trace__fprintf_callchain(trace, sample);
2062 else if (callchain_ret < 0)
2063 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
2064out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002065 return 0;
2066}
2067
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002068static void print_location(FILE *f, struct perf_sample *sample,
2069 struct addr_location *al,
2070 bool print_dso, bool print_sym)
2071{
2072
2073 if ((verbose || print_dso) && al->map)
2074 fprintf(f, "%s@", al->map->dso->long_name);
2075
2076 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002077 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002078 al->addr - al->sym->start);
2079 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002080 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002081 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002082 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002083}
2084
2085static int trace__pgfault(struct trace *trace,
2086 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002087 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002088 struct perf_sample *sample)
2089{
2090 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002091 struct addr_location al;
2092 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002093 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002094 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002095 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002096
2097 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002098
2099 if (sample->callchain) {
2100 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2101 if (callchain_ret == 0) {
2102 if (callchain_cursor.nr < trace->min_stack)
2103 goto out_put;
2104 callchain_ret = 1;
2105 }
2106 }
2107
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002108 ttrace = thread__trace(thread, trace->output);
2109 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002110 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002111
2112 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2113 ttrace->pfmaj++;
2114 else
2115 ttrace->pfmin++;
2116
2117 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002118 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002119
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002120 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002121 sample->ip, &al);
2122
2123 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2124
2125 fprintf(trace->output, "%sfault [",
2126 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2127 "maj" : "min");
2128
2129 print_location(trace->output, sample, &al, false, true);
2130
2131 fprintf(trace->output, "] => ");
2132
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002133 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002134 sample->addr, &al);
2135
2136 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002137 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002138 MAP__FUNCTION, sample->addr, &al);
2139
2140 if (al.map)
2141 map_type = 'x';
2142 else
2143 map_type = '?';
2144 }
2145
2146 print_location(trace->output, sample, &al, true, false);
2147
2148 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002149
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002150 if (callchain_ret > 0)
2151 trace__fprintf_callchain(trace, sample);
2152 else if (callchain_ret < 0)
2153 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002154out:
2155 err = 0;
2156out_put:
2157 thread__put(thread);
2158 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002159}
2160
David Ahernbdc89662013-08-28 22:29:53 -06002161static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2162{
2163 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2164 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2165 return false;
2166
2167 if (trace->pid_list || trace->tid_list)
2168 return true;
2169
2170 return false;
2171}
2172
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002173static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002174 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002175 struct perf_sample *sample)
2176{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002177 /*
2178 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2179 * and don't use sample->time unconditionally, we may end up having
2180 * some other event in the future without PERF_SAMPLE_TIME for good
2181 * reason, i.e. we may not be interested in its timestamps, just in
2182 * it taking place, picking some piece of information when it
2183 * appears in our event stream (vfs_getname comes to mind).
2184 */
2185 if (trace->base_time == 0 && !trace->full_time &&
2186 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002187 trace->base_time = sample->time;
2188}
2189
David Ahern6810fc92013-08-28 22:29:52 -06002190static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002191 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002192 struct perf_sample *sample,
2193 struct perf_evsel *evsel,
2194 struct machine *machine __maybe_unused)
2195{
2196 struct trace *trace = container_of(tool, struct trace, tool);
2197 int err = 0;
2198
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002199 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002200
David Ahernbdc89662013-08-28 22:29:53 -06002201 if (skip_sample(trace, sample))
2202 return 0;
2203
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002204 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002205
David Ahern31605652013-12-04 19:41:41 -07002206 if (handler) {
2207 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002208 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002209 }
David Ahern6810fc92013-08-28 22:29:52 -06002210
2211 return err;
2212}
2213
David Ahernbdc89662013-08-28 22:29:53 -06002214static int parse_target_str(struct trace *trace)
2215{
2216 if (trace->opts.target.pid) {
2217 trace->pid_list = intlist__new(trace->opts.target.pid);
2218 if (trace->pid_list == NULL) {
2219 pr_err("Error parsing process id string\n");
2220 return -EINVAL;
2221 }
2222 }
2223
2224 if (trace->opts.target.tid) {
2225 trace->tid_list = intlist__new(trace->opts.target.tid);
2226 if (trace->tid_list == NULL) {
2227 pr_err("Error parsing thread id string\n");
2228 return -EINVAL;
2229 }
2230 }
2231
2232 return 0;
2233}
2234
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002235static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002236{
2237 unsigned int rec_argc, i, j;
2238 const char **rec_argv;
2239 const char * const record_args[] = {
2240 "record",
2241 "-R",
2242 "-m", "1024",
2243 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002244 };
2245
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002246 const char * const sc_args[] = { "-e", };
2247 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2248 const char * const majpf_args[] = { "-e", "major-faults" };
2249 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2250 const char * const minpf_args[] = { "-e", "minor-faults" };
2251 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2252
David Ahern9aca7f12013-12-04 19:41:39 -07002253 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002254 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2255 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002256 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2257
2258 if (rec_argv == NULL)
2259 return -ENOMEM;
2260
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002261 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002262 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002263 rec_argv[j++] = record_args[i];
2264
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002265 if (trace->trace_syscalls) {
2266 for (i = 0; i < sc_args_nr; i++)
2267 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002268
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002269 /* event string may be different for older kernels - e.g., RHEL6 */
2270 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2271 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2272 else if (is_valid_tracepoint("syscalls:sys_enter"))
2273 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2274 else {
2275 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2276 return -1;
2277 }
David Ahern9aca7f12013-12-04 19:41:39 -07002278 }
David Ahern9aca7f12013-12-04 19:41:39 -07002279
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002280 if (trace->trace_pgfaults & TRACE_PFMAJ)
2281 for (i = 0; i < majpf_args_nr; i++)
2282 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002283
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002284 if (trace->trace_pgfaults & TRACE_PFMIN)
2285 for (i = 0; i < minpf_args_nr; i++)
2286 rec_argv[j++] = minpf_args[i];
2287
2288 for (i = 0; i < (unsigned int)argc; i++)
2289 rec_argv[j++] = argv[i];
2290
2291 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002292}
2293
David Ahernbf2575c2013-10-08 21:26:53 -06002294static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2295
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002296static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002297{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002298 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002299
2300 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002301 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002302
2303 if (perf_evsel__field(evsel, "pathname") == NULL) {
2304 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002305 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002306 }
2307
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002308 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002309 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002310 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002311}
2312
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002313static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002314{
2315 struct perf_evsel *evsel;
2316 struct perf_event_attr attr = {
2317 .type = PERF_TYPE_SOFTWARE,
2318 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002319 };
2320
2321 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002322 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002323
2324 event_attr_init(&attr);
2325
2326 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002327 if (evsel)
2328 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002329
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002330 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002331}
2332
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002333static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2334{
2335 const u32 type = event->header.type;
2336 struct perf_evsel *evsel;
2337
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002338 if (type != PERF_RECORD_SAMPLE) {
2339 trace__process_event(trace, trace->host, event, sample);
2340 return;
2341 }
2342
2343 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2344 if (evsel == NULL) {
2345 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2346 return;
2347 }
2348
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002349 trace__set_base_time(trace, evsel, sample);
2350
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002351 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2352 sample->raw_data == NULL) {
2353 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2354 perf_evsel__name(evsel), sample->tid,
2355 sample->cpu, sample->raw_size);
2356 } else {
2357 tracepoint_handler handler = evsel->handler;
2358 handler(trace, evsel, event, sample);
2359 }
2360}
2361
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002362static int trace__add_syscall_newtp(struct trace *trace)
2363{
2364 int ret = -1;
2365 struct perf_evlist *evlist = trace->evlist;
2366 struct perf_evsel *sys_enter, *sys_exit;
2367
2368 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2369 if (sys_enter == NULL)
2370 goto out;
2371
2372 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2373 goto out_delete_sys_enter;
2374
2375 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2376 if (sys_exit == NULL)
2377 goto out_delete_sys_enter;
2378
2379 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2380 goto out_delete_sys_exit;
2381
2382 perf_evlist__add(evlist, sys_enter);
2383 perf_evlist__add(evlist, sys_exit);
2384
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002385 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002386 /*
2387 * We're interested only in the user space callchain
2388 * leading to the syscall, allow overriding that for
2389 * debugging reasons using --kernel_syscall_callchains
2390 */
2391 sys_exit->attr.exclude_callchain_kernel = 1;
2392 }
2393
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002394 trace->syscalls.events.sys_enter = sys_enter;
2395 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002396
2397 ret = 0;
2398out:
2399 return ret;
2400
2401out_delete_sys_exit:
2402 perf_evsel__delete_priv(sys_exit);
2403out_delete_sys_enter:
2404 perf_evsel__delete_priv(sys_enter);
2405 goto out;
2406}
2407
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002408static int trace__set_ev_qualifier_filter(struct trace *trace)
2409{
2410 int err = -1;
2411 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2412 trace->ev_qualifier_ids.nr,
2413 trace->ev_qualifier_ids.entries);
2414
2415 if (filter == NULL)
2416 goto out_enomem;
2417
2418 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2419 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2420
2421 free(filter);
2422out:
2423 return err;
2424out_enomem:
2425 errno = ENOMEM;
2426 goto out;
2427}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002428
Namhyung Kimf15eb532012-10-05 14:02:16 +09002429static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002430{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002431 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002432 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002433 int err = -1, i;
2434 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002435 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002436 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002437
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002438 trace->live = true;
2439
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002440 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002441 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002442
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002443 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002444 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002445
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002446 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2447 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2448 if (pgfault_maj == NULL)
2449 goto out_error_mem;
2450 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002451 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002452
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002453 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2454 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2455 if (pgfault_min == NULL)
2456 goto out_error_mem;
2457 perf_evlist__add(evlist, pgfault_min);
2458 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002459
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002460 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002461 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2462 trace__sched_stat_runtime))
2463 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002464
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002465 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2466 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002467 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002468 goto out_delete_evlist;
2469 }
2470
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002471 err = trace__symbols_init(trace, evlist);
2472 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002473 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002474 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002475 }
2476
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002477 perf_evlist__config(evlist, &trace->opts, NULL);
2478
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002479 if (callchain_param.enabled) {
2480 bool use_identifier = false;
2481
2482 if (trace->syscalls.events.sys_exit) {
2483 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2484 &trace->opts, &callchain_param);
2485 use_identifier = true;
2486 }
2487
2488 if (pgfault_maj) {
2489 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2490 use_identifier = true;
2491 }
2492
2493 if (pgfault_min) {
2494 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2495 use_identifier = true;
2496 }
2497
2498 if (use_identifier) {
2499 /*
2500 * Now we have evsels with different sample_ids, use
2501 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2502 * from a fixed position in each ring buffer record.
2503 *
2504 * As of this the changeset introducing this comment, this
2505 * isn't strictly needed, as the fields that can come before
2506 * PERF_SAMPLE_ID are all used, but we'll probably disable
2507 * some of those for things like copying the payload of
2508 * pointer syscall arguments, and for vfs_getname we don't
2509 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2510 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2511 */
2512 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2513 perf_evlist__reset_sample_bit(evlist, ID);
2514 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002515 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002516
Namhyung Kimf15eb532012-10-05 14:02:16 +09002517 signal(SIGCHLD, sig_handler);
2518 signal(SIGINT, sig_handler);
2519
2520 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002521 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002522 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002523 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002524 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002525 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002526 }
2527 }
2528
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002529 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002530 if (err < 0)
2531 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002532
Wang Nanba504232016-02-26 09:31:54 +00002533 err = bpf__apply_obj_config();
2534 if (err) {
2535 char errbuf[BUFSIZ];
2536
2537 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2538 pr_err("ERROR: Apply config to BPF failed: %s\n",
2539 errbuf);
2540 goto out_error_open;
2541 }
2542
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:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002654 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002655 goto out_error;
2656
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002657out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002658 tracing_path__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 Olsaf5fc14122013-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 Olsaf5fc14122013-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 Olsaf5fc14122013-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
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002793DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2794 struct stats *stats;
2795 double msecs;
2796 int syscall;
2797)
2798{
2799 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2800 struct stats *stats = source->priv;
2801
2802 entry->syscall = source->i;
2803 entry->stats = stats;
2804 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2805}
2806
David Ahernbf2575c2013-10-08 21:26:53 -06002807static size_t thread__dump_stats(struct thread_trace *ttrace,
2808 struct trace *trace, FILE *fp)
2809{
David Ahernbf2575c2013-10-08 21:26:53 -06002810 size_t printed = 0;
2811 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002812 struct rb_node *nd;
2813 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002814
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002815 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002816 return 0;
2817
2818 printed += fprintf(fp, "\n");
2819
Milian Wolff834fd462015-08-06 11:24:29 +02002820 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2821 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2822 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002823
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002824 resort_rb__for_each(nd, syscall_stats) {
2825 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002826 if (stats) {
2827 double min = (double)(stats->min) / NSEC_PER_MSEC;
2828 double max = (double)(stats->max) / NSEC_PER_MSEC;
2829 double avg = avg_stats(stats);
2830 double pct;
2831 u64 n = (u64) stats->n;
2832
2833 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2834 avg /= NSEC_PER_MSEC;
2835
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002836 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002837 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002838 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002839 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002840 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002841 }
David Ahernbf2575c2013-10-08 21:26:53 -06002842 }
2843
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002844 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002845 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002846
2847 return printed;
2848}
2849
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002850static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002851{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002852 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002853 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002854 double ratio;
2855
2856 if (ttrace == NULL)
2857 return 0;
2858
2859 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2860
Pekka Enberg15e65c62013-11-14 18:43:30 +02002861 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002862 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002863 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002864 if (ttrace->pfmaj)
2865 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2866 if (ttrace->pfmin)
2867 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002868 if (trace->sched)
2869 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2870 else if (fputc('\n', fp) != EOF)
2871 ++printed;
2872
David Ahernbf2575c2013-10-08 21:26:53 -06002873 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002874
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002875 return printed;
2876}
David Ahern896cbb52013-09-28 13:12:59 -06002877
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002878static unsigned long thread__nr_events(struct thread_trace *ttrace)
2879{
2880 return ttrace ? ttrace->nr_events : 0;
2881}
2882
2883DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2884 struct thread *thread;
2885)
2886{
2887 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002888}
2889
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002890static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2891{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002892 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2893 size_t printed = trace__fprintf_threads_header(fp);
2894 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002895
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002896 if (threads == NULL) {
2897 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2898 return 0;
2899 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002900
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002901 resort_rb__for_each(nd, threads)
2902 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2903
2904 resort_rb__delete(threads);
2905
2906 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002907}
2908
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002909static int trace__set_duration(const struct option *opt, const char *str,
2910 int unset __maybe_unused)
2911{
2912 struct trace *trace = opt->value;
2913
2914 trace->duration_filter = atof(str);
2915 return 0;
2916}
2917
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002918static int trace__set_filter_pids(const struct option *opt, const char *str,
2919 int unset __maybe_unused)
2920{
2921 int ret = -1;
2922 size_t i;
2923 struct trace *trace = opt->value;
2924 /*
2925 * FIXME: introduce a intarray class, plain parse csv and create a
2926 * { int nr, int entries[] } struct...
2927 */
2928 struct intlist *list = intlist__new(str);
2929
2930 if (list == NULL)
2931 return -1;
2932
2933 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2934 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2935
2936 if (trace->filter_pids.entries == NULL)
2937 goto out;
2938
2939 trace->filter_pids.entries[0] = getpid();
2940
2941 for (i = 1; i < trace->filter_pids.nr; ++i)
2942 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2943
2944 intlist__delete(list);
2945 ret = 0;
2946out:
2947 return ret;
2948}
2949
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002950static int trace__open_output(struct trace *trace, const char *filename)
2951{
2952 struct stat st;
2953
2954 if (!stat(filename, &st) && st.st_size) {
2955 char oldname[PATH_MAX];
2956
2957 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2958 unlink(oldname);
2959 rename(filename, oldname);
2960 }
2961
2962 trace->output = fopen(filename, "w");
2963
2964 return trace->output == NULL ? -errno : 0;
2965}
2966
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002967static int parse_pagefaults(const struct option *opt, const char *str,
2968 int unset __maybe_unused)
2969{
2970 int *trace_pgfaults = opt->value;
2971
2972 if (strcmp(str, "all") == 0)
2973 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2974 else if (strcmp(str, "maj") == 0)
2975 *trace_pgfaults |= TRACE_PFMAJ;
2976 else if (strcmp(str, "min") == 0)
2977 *trace_pgfaults |= TRACE_PFMIN;
2978 else
2979 return -1;
2980
2981 return 0;
2982}
2983
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002984static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2985{
2986 struct perf_evsel *evsel;
2987
2988 evlist__for_each(evlist, evsel)
2989 evsel->handler = handler;
2990}
2991
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002992int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2993{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002994 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002995 "perf trace [<options>] [<command>]",
2996 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002997 "perf trace record [<options>] [<command>]",
2998 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002999 NULL
3000 };
3001 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003002 .syscalls = {
3003 . max = -1,
3004 },
3005 .opts = {
3006 .target = {
3007 .uid = UINT_MAX,
3008 .uses_mmap = true,
3009 },
3010 .user_freq = UINT_MAX,
3011 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003012 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003013 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003014 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003015 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003016 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003017 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003018 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003019 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003020 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003021 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003022 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003023 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003024 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003025 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3026 "event selector. use 'perf list' to list available events",
3027 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003028 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3029 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003030 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03003031 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003032 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003033 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003034 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3035 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003036 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003037 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003038 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3039 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003040 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003041 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003042 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003043 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003044 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003045 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003046 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3047 "number of mmap data pages",
3048 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003049 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003050 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003051 OPT_CALLBACK(0, "duration", &trace, "float",
3052 "show only events with duration > N.M ms",
3053 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003054 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003055 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003056 OPT_BOOLEAN('T', "time", &trace.full_time,
3057 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003058 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3059 "Show only syscall summary with statistics"),
3060 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3061 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003062 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3063 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003064 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003065 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003066 OPT_CALLBACK(0, "call-graph", &trace.opts,
3067 "record_mode[,record_size]", record_callchain_help,
3068 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003069 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3070 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03003071 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3072 "Set the minimum stack depth when parsing the callchain, "
3073 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03003074 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3075 "Set the maximum stack depth when parsing the callchain, "
3076 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03003077 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04003078 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3079 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003080 OPT_END()
3081 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003082 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003083 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003084 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003085 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003086 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003087
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003088 signal(SIGSEGV, sighandler_dump_stack);
3089 signal(SIGFPE, sighandler_dump_stack);
3090
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003091 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003092 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003093
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003094 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003095 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003096 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003097 goto out;
3098 }
3099
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003100 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3101 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003102
Wang Nand7888572016-04-08 15:07:24 +00003103 err = bpf__setup_stdout(trace.evlist);
3104 if (err) {
3105 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3106 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3107 goto out;
3108 }
3109
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003110 err = -1;
3111
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003112 if (trace.trace_pgfaults) {
3113 trace.opts.sample_address = true;
3114 trace.opts.sample_time = true;
3115 }
3116
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003117 if (trace.opts.mmap_pages == UINT_MAX)
3118 mmap_pages_user_set = false;
3119
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003120 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03003121 trace.max_stack = sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003122 max_stack_user_set = false;
3123 }
3124
3125#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003126 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003127 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
3128#endif
3129
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003130 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003131 if (!mmap_pages_user_set && geteuid() == 0)
3132 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3133
Milian Wolff566a0882016-04-08 13:34:15 +02003134 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003135 }
Milian Wolff566a0882016-04-08 13:34:15 +02003136
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003137 if (trace.evlist->nr_entries > 0)
3138 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3139
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003140 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3141 return trace__record(&trace, argc-1, &argv[1]);
3142
3143 /* summary_only implies summary option, but don't overwrite summary if set */
3144 if (trace.summary_only)
3145 trace.summary = trace.summary_only;
3146
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003147 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3148 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003149 pr_err("Please specify something to trace.\n");
3150 return -1;
3151 }
3152
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003153 if (!trace.trace_syscalls && ev_qualifier_str) {
3154 pr_err("The -e option can't be used with --no-syscalls.\n");
3155 goto out;
3156 }
3157
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003158 if (output_name != NULL) {
3159 err = trace__open_output(&trace, output_name);
3160 if (err < 0) {
3161 perror("failed to create output file");
3162 goto out;
3163 }
3164 }
3165
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003166 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3167
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003168 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003169 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03003170 struct strlist_config slist_config = {
3171 .dirname = system_path(STRACE_GROUPS_DIR),
3172 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003173
3174 trace.not_ev_qualifier = *s == '!';
3175 if (trace.not_ev_qualifier)
3176 ++s;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03003177 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003178 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003179 fputs("Not enough memory to parse event qualifier",
3180 trace.output);
3181 err = -ENOMEM;
3182 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003183 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003184
3185 err = trace__validate_ev_qualifier(&trace);
3186 if (err)
3187 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003188 }
3189
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003190 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003191 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003192 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003193 fprintf(trace.output, "%s", bf);
3194 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003195 }
3196
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003197 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003198 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003199 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003200 fprintf(trace.output, "%s", bf);
3201 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003202 }
3203
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003204 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003205 trace.opts.target.system_wide = true;
3206
David Ahern6810fc92013-08-28 22:29:52 -06003207 if (input_name)
3208 err = trace__replay(&trace);
3209 else
3210 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003211
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003212out_close:
3213 if (output_name != NULL)
3214 fclose(trace.output);
3215out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003216 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003217}