blob: e7f2697e7ca6927b94441e45353c04bf92f568ba [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 Ahern55d43bc2015-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 Ahern55d43bc2015-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 Melo844ae5b2014-02-10 14:09:48 -0300624#if defined(__i386__) || defined(__x86_64__)
625/*
626 * FIXME: Make this available to all arches.
627 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300628#define TCGETS 0x5401
629
630static const char *tioctls[] = {
631 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
632 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
633 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
634 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
635 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
636 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
637 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
638 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
639 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
640 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
641 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
642 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
643 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
644 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
645 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
646};
647
648static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300649#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300650
Arnaldo Carvalho de Melo6fb35b92016-04-13 11:50:23 -0300651#ifndef SECCOMP_SET_MODE_STRICT
652#define SECCOMP_SET_MODE_STRICT 0
653#endif
654#ifndef SECCOMP_SET_MODE_FILTER
655#define SECCOMP_SET_MODE_FILTER 1
656#endif
657
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300658static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg)
659{
660 int op = arg->val;
661 size_t printed = 0;
662
663 switch (op) {
664#define P_SECCOMP_SET_MODE_OP(n) case SECCOMP_SET_MODE_##n: printed = scnprintf(bf, size, #n); break
665 P_SECCOMP_SET_MODE_OP(STRICT);
666 P_SECCOMP_SET_MODE_OP(FILTER);
667#undef P_SECCOMP_SET_MODE_OP
668 default: printed = scnprintf(bf, size, "%#x", op); break;
669 }
670
671 return printed;
672}
673
674#define SCA_SECCOMP_OP syscall_arg__scnprintf_seccomp_op
675
Arnaldo Carvalho de Melo6fb35b92016-04-13 11:50:23 -0300676#ifndef SECCOMP_FILTER_FLAG_TSYNC
677#define SECCOMP_FILTER_FLAG_TSYNC 1
678#endif
679
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300680static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size,
681 struct syscall_arg *arg)
682{
683 int printed = 0, flags = arg->val;
684
685#define P_FLAG(n) \
686 if (flags & SECCOMP_FILTER_FLAG_##n) { \
687 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
688 flags &= ~SECCOMP_FILTER_FLAG_##n; \
689 }
690
691 P_FLAG(TSYNC);
692#undef P_FLAG
693
694 if (flags)
695 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
696
697 return printed;
698}
699
700#define SCA_SECCOMP_FLAGS syscall_arg__scnprintf_seccomp_flags
701
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300702#ifndef GRND_NONBLOCK
703#define GRND_NONBLOCK 0x0001
704#endif
705#ifndef GRND_RANDOM
706#define GRND_RANDOM 0x0002
707#endif
708
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300709static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
710 struct syscall_arg *arg)
711{
712 int printed = 0, flags = arg->val;
713
714#define P_FLAG(n) \
715 if (flags & GRND_##n) { \
716 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
717 flags &= ~GRND_##n; \
718 }
719
720 P_FLAG(RANDOM);
721 P_FLAG(NONBLOCK);
722#undef P_FLAG
723
724 if (flags)
725 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
726
727 return printed;
728}
729
730#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
731
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300732#define STRARRAY(arg, name, array) \
733 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
734 .arg_parm = { [arg] = &strarray__##array, }
735
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300736#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300737#include "trace/beauty/pid.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300738#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300739#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300740#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300741#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300742#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300743#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300744#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300745#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300746
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300747static struct syscall_fmt {
748 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300749 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300750 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300751 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300752 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300753 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300754 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300755 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300756} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300757 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300758 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
759 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300760 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300761 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300762 { .name = "brk", .hexret = true,
763 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300764 { .name = "chdir", .errmsg = true,
765 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
766 { .name = "chmod", .errmsg = true,
767 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
768 { .name = "chroot", .errmsg = true,
769 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600770 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300771 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300772 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300773 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300774 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300775 { .name = "creat", .errmsg = true,
776 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300777 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300778 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300779 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300780 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300781 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300782 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300783 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300784 { .name = "eventfd2", .errmsg = true,
785 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300786 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300787 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
788 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300789 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300790 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300791 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300792 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300793 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300794 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300795 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300796 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300797 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300798 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
799 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300800 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300801 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300802 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300803 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
804 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300805 { .name = "fcntl", .errmsg = true,
806 .arg_scnprintf = { [0] = SCA_FD, /* fd */
807 [1] = SCA_STRARRAY, /* cmd */ },
808 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
809 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300810 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300811 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300812 .arg_scnprintf = { [0] = SCA_FD, /* fd */
813 [1] = SCA_FLOCK, /* cmd */ }, },
814 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300815 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300816 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300817 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300818 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300819 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
820 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300821 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300822 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300823 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300824 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300825 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300826 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300827 { .name = "futex", .errmsg = true,
828 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300829 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300830 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
831 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300832 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300833 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300834 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300835 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300836 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300837 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300838 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300839 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300840 { .name = "getrandom", .errmsg = true,
841 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300842 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300843 { .name = "getxattr", .errmsg = true,
844 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
845 { .name = "inotify_add_watch", .errmsg = true,
846 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300847 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300848 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300849#if defined(__i386__) || defined(__x86_64__)
850/*
851 * FIXME: Make this available to all arches.
852 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300853 [1] = SCA_STRHEXARRAY, /* cmd */
854 [2] = SCA_HEX, /* arg */ },
855 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300856#else
857 [2] = SCA_HEX, /* arg */ }, },
858#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300859 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300860 { .name = "kill", .errmsg = true,
861 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300862 { .name = "lchown", .errmsg = true,
863 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
864 { .name = "lgetxattr", .errmsg = true,
865 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300866 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300867 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300868 { .name = "listxattr", .errmsg = true,
869 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300870 { .name = "llistxattr", .errmsg = true,
871 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
872 { .name = "lremovexattr", .errmsg = true,
873 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300874 { .name = "lseek", .errmsg = true,
875 .arg_scnprintf = { [0] = SCA_FD, /* fd */
876 [2] = SCA_STRARRAY, /* whence */ },
877 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300878 { .name = "lsetxattr", .errmsg = true,
879 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300880 { .name = "lstat", .errmsg = true, .alias = "newlstat",
881 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300882 { .name = "lsxattr", .errmsg = true,
883 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300884 { .name = "madvise", .errmsg = true,
885 .arg_scnprintf = { [0] = SCA_HEX, /* start */
886 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300887 { .name = "mkdir", .errmsg = true,
888 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300889 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300890 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
891 [1] = SCA_FILENAME, /* pathname */ }, },
892 { .name = "mknod", .errmsg = true,
893 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300894 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300895 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
896 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300897 { .name = "mlock", .errmsg = true,
898 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
899 { .name = "mlockall", .errmsg = true,
900 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300901 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300902 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300903 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +0900904 [3] = SCA_MMAP_FLAGS, /* flags */
905 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300906 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300907 .arg_scnprintf = { [0] = SCA_HEX, /* start */
908 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300909 { .name = "mq_unlink", .errmsg = true,
910 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300911 { .name = "mremap", .hexret = true,
912 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +0300913 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300914 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300915 { .name = "munlock", .errmsg = true,
916 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300917 { .name = "munmap", .errmsg = true,
918 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300919 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300920 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300921 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300922 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
923 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300924 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300925 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
926 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300927 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300928 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
929 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300930 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300931 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300932 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300933 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300934 { .name = "perf_event_open", .errmsg = true,
Arnaldo Carvalho de Meloccd9b2a2016-04-26 11:40:17 -0300935 .arg_scnprintf = { [2] = SCA_INT, /* cpu */
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300936 [3] = SCA_FD, /* group_fd */
937 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300938 { .name = "pipe2", .errmsg = true,
939 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300940 { .name = "poll", .errmsg = true, .timeout = true, },
941 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300942 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300943 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300944 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300945 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300946 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300947 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300948 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300949 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300950 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300951 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300952 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300953 { .name = "readlink", .errmsg = true,
954 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300955 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300956 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
957 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300958 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300959 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300960 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -0300961 .arg_scnprintf = { [0] = SCA_FD, /* fd */
962 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300963 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -0300964 .arg_scnprintf = { [0] = SCA_FD, /* fd */
965 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300966 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -0300967 .arg_scnprintf = { [0] = SCA_FD, /* fd */
968 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300969 { .name = "removexattr", .errmsg = true,
970 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300971 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300972 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300973 { .name = "rmdir", .errmsg = true,
974 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300975 { .name = "rt_sigaction", .errmsg = true,
976 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300977 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300978 { .name = "rt_sigqueueinfo", .errmsg = true,
979 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
980 { .name = "rt_tgsigqueueinfo", .errmsg = true,
981 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300982 { .name = "sched_setscheduler", .errmsg = true,
983 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300984 { .name = "seccomp", .errmsg = true,
985 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
986 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300987 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300988 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -0300989 .arg_scnprintf = { [0] = SCA_FD, /* fd */
990 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300991 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -0300992 .arg_scnprintf = { [0] = SCA_FD, /* fd */
993 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300994 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -0300995 .arg_scnprintf = { [0] = SCA_FD, /* fd */
996 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300997 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300998 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300999 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001000 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001001 { .name = "setxattr", .errmsg = true,
1002 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001003 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001004 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001005 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001006 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1007 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001008 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001009 { .name = "socketpair", .errmsg = true,
1010 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1011 [1] = SCA_SK_TYPE, /* type */ },
1012 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001013 { .name = "stat", .errmsg = true, .alias = "newstat",
1014 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001015 { .name = "statfs", .errmsg = true,
1016 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1017 { .name = "swapoff", .errmsg = true,
1018 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1019 { .name = "swapon", .errmsg = true,
1020 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001021 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001022 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001023 { .name = "tgkill", .errmsg = true,
1024 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1025 { .name = "tkill", .errmsg = true,
1026 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001027 { .name = "truncate", .errmsg = true,
1028 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001029 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001030 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001031 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1032 [1] = SCA_FILENAME, /* pathname */ }, },
1033 { .name = "utime", .errmsg = true,
1034 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001035 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001036 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1037 [1] = SCA_FILENAME, /* filename */ }, },
1038 { .name = "utimes", .errmsg = true,
1039 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001040 { .name = "vmsplice", .errmsg = true,
1041 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001042 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001043 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001044 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001045 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001046 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001047 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001048 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001049 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001050};
1051
1052static int syscall_fmt__cmp(const void *name, const void *fmtp)
1053{
1054 const struct syscall_fmt *fmt = fmtp;
1055 return strcmp(name, fmt->name);
1056}
1057
1058static struct syscall_fmt *syscall_fmt__find(const char *name)
1059{
1060 const int nmemb = ARRAY_SIZE(syscall_fmts);
1061 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1062}
1063
1064struct syscall {
1065 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001066 int nr_args;
1067 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001068 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001069 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001070 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001071 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001072 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001073};
1074
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001075static size_t fprintf_duration(unsigned long t, FILE *fp)
1076{
1077 double duration = (double)t / NSEC_PER_MSEC;
1078 size_t printed = fprintf(fp, "(");
1079
1080 if (duration >= 1.0)
1081 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1082 else if (duration >= 0.01)
1083 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1084 else
1085 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001086 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001087}
1088
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001089/**
1090 * filename.ptr: The filename char pointer that will be vfs_getname'd
1091 * filename.entry_str_pos: Where to insert the string translated from
1092 * filename.ptr by the vfs_getname tracepoint/kprobe.
1093 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001094struct thread_trace {
1095 u64 entry_time;
1096 u64 exit_time;
1097 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001098 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001099 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001100 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001101 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001102 struct {
1103 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001104 short int entry_str_pos;
1105 bool pending_open;
1106 unsigned int namelen;
1107 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001108 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001109 struct {
1110 int max;
1111 char **table;
1112 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001113
1114 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001115};
1116
1117static struct thread_trace *thread_trace__new(void)
1118{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001119 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1120
1121 if (ttrace)
1122 ttrace->paths.max = -1;
1123
David Ahernbf2575c2013-10-08 21:26:53 -06001124 ttrace->syscall_stats = intlist__new(NULL);
1125
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001126 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001127}
1128
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001129static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001130{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001131 struct thread_trace *ttrace;
1132
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001133 if (thread == NULL)
1134 goto fail;
1135
Namhyung Kim89dceb22014-10-06 09:46:03 +09001136 if (thread__priv(thread) == NULL)
1137 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001138
Namhyung Kim89dceb22014-10-06 09:46:03 +09001139 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001140 goto fail;
1141
Namhyung Kim89dceb22014-10-06 09:46:03 +09001142 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001143 ++ttrace->nr_events;
1144
1145 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001146fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001147 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001148 "WARNING: not enough memory, dropping samples!\n");
1149 return NULL;
1150}
1151
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001152#define TRACE_PFMAJ (1 << 0)
1153#define TRACE_PFMIN (1 << 1)
1154
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001155static const size_t trace__entry_str_size = 2048;
1156
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001157static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001158{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001159 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001160
1161 if (fd > ttrace->paths.max) {
1162 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1163
1164 if (npath == NULL)
1165 return -1;
1166
1167 if (ttrace->paths.max != -1) {
1168 memset(npath + ttrace->paths.max + 1, 0,
1169 (fd - ttrace->paths.max) * sizeof(char *));
1170 } else {
1171 memset(npath, 0, (fd + 1) * sizeof(char *));
1172 }
1173
1174 ttrace->paths.table = npath;
1175 ttrace->paths.max = fd;
1176 }
1177
1178 ttrace->paths.table[fd] = strdup(pathname);
1179
1180 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1181}
1182
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001183static int thread__read_fd_path(struct thread *thread, int fd)
1184{
1185 char linkname[PATH_MAX], pathname[PATH_MAX];
1186 struct stat st;
1187 int ret;
1188
1189 if (thread->pid_ == thread->tid) {
1190 scnprintf(linkname, sizeof(linkname),
1191 "/proc/%d/fd/%d", thread->pid_, fd);
1192 } else {
1193 scnprintf(linkname, sizeof(linkname),
1194 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1195 }
1196
1197 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1198 return -1;
1199
1200 ret = readlink(linkname, pathname, sizeof(pathname));
1201
1202 if (ret < 0 || ret > st.st_size)
1203 return -1;
1204
1205 pathname[ret] = '\0';
1206 return trace__set_fd_pathname(thread, fd, pathname);
1207}
1208
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001209static const char *thread__fd_path(struct thread *thread, int fd,
1210 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001211{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001212 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001213
1214 if (ttrace == NULL)
1215 return NULL;
1216
1217 if (fd < 0)
1218 return NULL;
1219
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001220 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001221 if (!trace->live)
1222 return NULL;
1223 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001224 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001225 return NULL;
1226 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001227
1228 return ttrace->paths.table[fd];
1229}
1230
1231static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1232 struct syscall_arg *arg)
1233{
1234 int fd = arg->val;
1235 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001236 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001237
1238 if (path)
1239 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1240
1241 return printed;
1242}
1243
1244static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1245 struct syscall_arg *arg)
1246{
1247 int fd = arg->val;
1248 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001249 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001250
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001251 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1252 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001253
1254 return printed;
1255}
1256
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001257static void thread__set_filename_pos(struct thread *thread, const char *bf,
1258 unsigned long ptr)
1259{
1260 struct thread_trace *ttrace = thread__priv(thread);
1261
1262 ttrace->filename.ptr = ptr;
1263 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1264}
1265
1266static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1267 struct syscall_arg *arg)
1268{
1269 unsigned long ptr = arg->val;
1270
1271 if (!arg->trace->vfs_getname)
1272 return scnprintf(bf, size, "%#x", ptr);
1273
1274 thread__set_filename_pos(arg->thread, bf, ptr);
1275 return 0;
1276}
1277
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001278static bool trace__filter_duration(struct trace *trace, double t)
1279{
1280 return t < (trace->duration_filter * NSEC_PER_MSEC);
1281}
1282
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001283static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1284{
1285 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1286
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001287 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001288}
1289
Namhyung Kimf15eb532012-10-05 14:02:16 +09001290static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001291static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001292
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001293static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001294{
1295 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001296 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001297}
1298
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001299static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001300 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001301{
1302 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001303 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001304
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001305 if (trace->multiple_threads) {
1306 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001307 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001308 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001309 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001310
1311 return printed;
1312}
1313
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001314static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001315 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001316{
1317 int ret = 0;
1318
1319 switch (event->header.type) {
1320 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001321 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001322 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001323 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001324 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001325 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001326 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001327 break;
1328 }
1329
1330 return ret;
1331}
1332
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001333static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001334 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001335 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001336 struct machine *machine)
1337{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001338 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001339 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001340}
1341
1342static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1343{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001344 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001345
1346 if (err)
1347 return err;
1348
David Ahern8fb598e2013-09-28 13:13:00 -06001349 trace->host = machine__new_host();
1350 if (trace->host == NULL)
1351 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001352
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001353 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001354 return -errno;
1355
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001356 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001357 evlist->threads, trace__tool_process, false,
1358 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001359 if (err)
1360 symbol__exit();
1361
1362 return err;
1363}
1364
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001365static int syscall__set_arg_fmts(struct syscall *sc)
1366{
1367 struct format_field *field;
1368 int idx = 0;
1369
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001370 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001371 if (sc->arg_scnprintf == NULL)
1372 return -1;
1373
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001374 if (sc->fmt)
1375 sc->arg_parm = sc->fmt->arg_parm;
1376
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001377 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001378 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1379 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1380 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001381 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001382 else if (strcmp(field->type, "pid_t") == 0)
1383 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001384 else if (strcmp(field->type, "umode_t") == 0)
1385 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001386 ++idx;
1387 }
1388
1389 return 0;
1390}
1391
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001392static int trace__read_syscall_info(struct trace *trace, int id)
1393{
1394 char tp_name[128];
1395 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001396 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001397
1398 if (name == NULL)
1399 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001400
1401 if (id > trace->syscalls.max) {
1402 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1403
1404 if (nsyscalls == NULL)
1405 return -1;
1406
1407 if (trace->syscalls.max != -1) {
1408 memset(nsyscalls + trace->syscalls.max + 1, 0,
1409 (id - trace->syscalls.max) * sizeof(*sc));
1410 } else {
1411 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1412 }
1413
1414 trace->syscalls.table = nsyscalls;
1415 trace->syscalls.max = id;
1416 }
1417
1418 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001419 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001420
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001421 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001422
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001423 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001424 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001425
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001426 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001427 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001428 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001429 }
1430
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001431 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001432 return -1;
1433
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001434 sc->args = sc->tp_format->format.fields;
1435 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001436 /*
1437 * We need to check and discard the first variable '__syscall_nr'
1438 * or 'nr' that mean the syscall number. It is needless here.
1439 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1440 */
1441 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001442 sc->args = sc->args->next;
1443 --sc->nr_args;
1444 }
1445
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001446 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1447
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001448 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001449}
1450
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001451static int trace__validate_ev_qualifier(struct trace *trace)
1452{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001453 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001454 struct str_node *pos;
1455
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001456 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1457 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1458 sizeof(trace->ev_qualifier_ids.entries[0]));
1459
1460 if (trace->ev_qualifier_ids.entries == NULL) {
1461 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1462 trace->output);
1463 err = -EINVAL;
1464 goto out;
1465 }
1466
1467 i = 0;
1468
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001469 strlist__for_each(pos, trace->ev_qualifier) {
1470 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001471 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001472
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001473 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001474 if (err == 0) {
1475 fputs("Error:\tInvalid syscall ", trace->output);
1476 err = -EINVAL;
1477 } else {
1478 fputs(", ", trace->output);
1479 }
1480
1481 fputs(sc, trace->output);
1482 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001483
1484 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001485 }
1486
1487 if (err < 0) {
1488 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1489 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001490 zfree(&trace->ev_qualifier_ids.entries);
1491 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001492 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001493out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001494 return err;
1495}
1496
David Ahern55d43bc2015-02-19 15:00:22 -05001497/*
1498 * args is to be interpreted as a series of longs but we need to handle
1499 * 8-byte unaligned accesses. args points to raw_data within the event
1500 * and raw_data is guaranteed to be 8-byte unaligned because it is
1501 * preceded by raw_size which is a u32. So we need to copy args to a temp
1502 * variable to read it. Most notably this avoids extended load instructions
1503 * on unaligned addresses
1504 */
1505
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001506static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001507 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001508 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001509{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001510 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001511 unsigned char *p;
1512 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001513
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001514 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001515 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001516 u8 bit = 1;
1517 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001518 .idx = 0,
1519 .mask = 0,
1520 .trace = trace,
1521 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001522 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001523
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001524 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001525 field = field->next, ++arg.idx, bit <<= 1) {
1526 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001527 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001528
1529 /* special care for unaligned accesses */
1530 p = args + sizeof(unsigned long) * arg.idx;
1531 memcpy(&val, p, sizeof(val));
1532
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001533 /*
1534 * Suppress this argument if its value is zero and
1535 * and we don't have a string associated in an
1536 * strarray for it.
1537 */
David Ahern55d43bc2015-02-19 15:00:22 -05001538 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001539 !(sc->arg_scnprintf &&
1540 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1541 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001542 continue;
1543
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001544 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001545 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001546 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001547 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001548 if (sc->arg_parm)
1549 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001550 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1551 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001552 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001553 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001554 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001555 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001556 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001557 } else if (IS_ERR(sc->tp_format)) {
1558 /*
1559 * If we managed to read the tracepoint /format file, then we
1560 * may end up not having any args, like with gettid(), so only
1561 * print the raw args when we didn't manage to read it.
1562 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001563 int i = 0;
1564
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001565 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001566 /* special care for unaligned accesses */
1567 p = args + sizeof(unsigned long) * i;
1568 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001569 printed += scnprintf(bf + printed, size - printed,
1570 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001571 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001572 ++i;
1573 }
1574 }
1575
1576 return printed;
1577}
1578
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001579typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001580 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001581 struct perf_sample *sample);
1582
1583static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001584 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001585{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001586
1587 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001588
1589 /*
1590 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1591 * before that, leaving at a higher verbosity level till that is
1592 * explained. Reproduced with plain ftrace with:
1593 *
1594 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1595 * grep "NR -1 " /t/trace_pipe
1596 *
1597 * After generating some load on the machine.
1598 */
1599 if (verbose > 1) {
1600 static u64 n;
1601 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1602 id, perf_evsel__name(evsel), ++n);
1603 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001604 return NULL;
1605 }
1606
1607 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1608 trace__read_syscall_info(trace, id))
1609 goto out_cant_read;
1610
1611 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1612 goto out_cant_read;
1613
1614 return &trace->syscalls.table[id];
1615
1616out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001617 if (verbose) {
1618 fprintf(trace->output, "Problems reading syscall %d", id);
1619 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1620 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1621 fputs(" information\n", trace->output);
1622 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001623 return NULL;
1624}
1625
David Ahernbf2575c2013-10-08 21:26:53 -06001626static void thread__update_stats(struct thread_trace *ttrace,
1627 int id, struct perf_sample *sample)
1628{
1629 struct int_node *inode;
1630 struct stats *stats;
1631 u64 duration = 0;
1632
1633 inode = intlist__findnew(ttrace->syscall_stats, id);
1634 if (inode == NULL)
1635 return;
1636
1637 stats = inode->priv;
1638 if (stats == NULL) {
1639 stats = malloc(sizeof(struct stats));
1640 if (stats == NULL)
1641 return;
1642 init_stats(stats);
1643 inode->priv = stats;
1644 }
1645
1646 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1647 duration = sample->time - ttrace->entry_time;
1648
1649 update_stats(stats, duration);
1650}
1651
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001652static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1653{
1654 struct thread_trace *ttrace;
1655 u64 duration;
1656 size_t printed;
1657
1658 if (trace->current == NULL)
1659 return 0;
1660
1661 ttrace = thread__priv(trace->current);
1662
1663 if (!ttrace->entry_pending)
1664 return 0;
1665
1666 duration = sample->time - ttrace->entry_time;
1667
1668 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1669 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1670 ttrace->entry_pending = false;
1671
1672 return printed;
1673}
1674
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001675static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001676 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001677 struct perf_sample *sample)
1678{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001679 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001680 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001681 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001682 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001683 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001684 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001685 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001686
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001687 if (sc == NULL)
1688 return -1;
1689
David Ahern8fb598e2013-09-28 13:13:00 -06001690 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001691 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001692 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001693 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001694
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001695 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001696
1697 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001698 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001699 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001700 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001701 }
1702
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001703 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001704 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001705
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001706 ttrace->entry_time = sample->time;
1707 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001708 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001709
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001710 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001711 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001712
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001713 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001714 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001715 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1716 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001717 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001718 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001719 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001720 /* See trace__vfs_getname & trace__sys_exit */
1721 ttrace->filename.pending_open = false;
1722 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001723
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001724 if (trace->current != thread) {
1725 thread__put(trace->current);
1726 trace->current = thread__get(thread);
1727 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001728 err = 0;
1729out_put:
1730 thread__put(thread);
1731 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001732}
1733
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001734static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1735 struct perf_sample *sample,
1736 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001737{
1738 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001739
1740 if (machine__resolve(trace->host, &al, sample) < 0 ||
1741 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1742 return -1;
1743
1744 return 0;
1745}
1746
1747static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1748{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001749 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001750 const unsigned int print_opts = EVSEL__PRINT_SYM |
1751 EVSEL__PRINT_DSO |
1752 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001753
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001754 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001755}
1756
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001757static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001758 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001759 struct perf_sample *sample)
1760{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001761 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001762 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001763 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001764 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001765 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001766 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001767
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001768 if (sc == NULL)
1769 return -1;
1770
David Ahern8fb598e2013-09-28 13:13:00 -06001771 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001772 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001773 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001774 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001775
David Ahernbf2575c2013-10-08 21:26:53 -06001776 if (trace->summary)
1777 thread__update_stats(ttrace, id, sample);
1778
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001779 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001780
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001781 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001782 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1783 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001784 ++trace->stats.vfs_getname;
1785 }
1786
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001787 ttrace->exit_time = sample->time;
1788
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001789 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001790 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001791 if (trace__filter_duration(trace, duration))
1792 goto out;
1793 } else if (trace->duration_filter)
1794 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001795
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001796 if (sample->callchain) {
1797 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1798 if (callchain_ret == 0) {
1799 if (callchain_cursor.nr < trace->min_stack)
1800 goto out;
1801 callchain_ret = 1;
1802 }
1803 }
1804
David Ahernfd2eaba2013-11-12 09:31:15 -07001805 if (trace->summary_only)
1806 goto out;
1807
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001808 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001809
1810 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001811 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001812 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001813 fprintf(trace->output, " ... [");
1814 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1815 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001816 }
1817
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001818 if (sc->fmt == NULL) {
1819signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001820 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001821 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001822 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001823 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1824 *e = audit_errno_to_name(-ret);
1825
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001826 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001827 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001828 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001829 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001830 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001831 else if (sc->fmt->errpid) {
1832 struct thread *child = machine__find_thread(trace->host, ret, ret);
1833
1834 if (child != NULL) {
1835 fprintf(trace->output, ") = %ld", ret);
1836 if (child->comm_set)
1837 fprintf(trace->output, " (%s)", thread__comm_str(child));
1838 thread__put(child);
1839 }
1840 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001841 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001842
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001843 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001844
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001845 if (callchain_ret > 0)
1846 trace__fprintf_callchain(trace, sample);
1847 else if (callchain_ret < 0)
1848 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001849out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001850 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001851 err = 0;
1852out_put:
1853 thread__put(thread);
1854 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001855}
1856
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001857static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001858 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001859 struct perf_sample *sample)
1860{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001861 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1862 struct thread_trace *ttrace;
1863 size_t filename_len, entry_str_len, to_move;
1864 ssize_t remaining_space;
1865 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001866 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001867
1868 if (!thread)
1869 goto out;
1870
1871 ttrace = thread__priv(thread);
1872 if (!ttrace)
1873 goto out;
1874
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001875 filename_len = strlen(filename);
1876
1877 if (ttrace->filename.namelen < filename_len) {
1878 char *f = realloc(ttrace->filename.name, filename_len + 1);
1879
1880 if (f == NULL)
1881 goto out;
1882
1883 ttrace->filename.namelen = filename_len;
1884 ttrace->filename.name = f;
1885 }
1886
1887 strcpy(ttrace->filename.name, filename);
1888 ttrace->filename.pending_open = true;
1889
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001890 if (!ttrace->filename.ptr)
1891 goto out;
1892
1893 entry_str_len = strlen(ttrace->entry_str);
1894 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1895 if (remaining_space <= 0)
1896 goto out;
1897
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001898 if (filename_len > (size_t)remaining_space) {
1899 filename += filename_len - remaining_space;
1900 filename_len = remaining_space;
1901 }
1902
1903 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1904 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1905 memmove(pos + filename_len, pos, to_move);
1906 memcpy(pos, filename, filename_len);
1907
1908 ttrace->filename.ptr = 0;
1909 ttrace->filename.entry_str_pos = 0;
1910out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001911 return 0;
1912}
1913
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001914static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001915 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001916 struct perf_sample *sample)
1917{
1918 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1919 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001920 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001921 sample->pid,
1922 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001923 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001924
1925 if (ttrace == NULL)
1926 goto out_dump;
1927
1928 ttrace->runtime_ms += runtime_ms;
1929 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001930 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001931 return 0;
1932
1933out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001934 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001935 evsel->name,
1936 perf_evsel__strval(evsel, sample, "comm"),
1937 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1938 runtime,
1939 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001940 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001941 return 0;
1942}
1943
Wang Nan1d6c9402016-02-26 09:31:55 +00001944static void bpf_output__printer(enum binary_printer_ops op,
1945 unsigned int val, void *extra)
1946{
1947 FILE *output = extra;
1948 unsigned char ch = (unsigned char)val;
1949
1950 switch (op) {
1951 case BINARY_PRINT_CHAR_DATA:
1952 fprintf(output, "%c", isprint(ch) ? ch : '.');
1953 break;
1954 case BINARY_PRINT_DATA_BEGIN:
1955 case BINARY_PRINT_LINE_BEGIN:
1956 case BINARY_PRINT_ADDR:
1957 case BINARY_PRINT_NUM_DATA:
1958 case BINARY_PRINT_NUM_PAD:
1959 case BINARY_PRINT_SEP:
1960 case BINARY_PRINT_CHAR_PAD:
1961 case BINARY_PRINT_LINE_END:
1962 case BINARY_PRINT_DATA_END:
1963 default:
1964 break;
1965 }
1966}
1967
1968static void bpf_output__fprintf(struct trace *trace,
1969 struct perf_sample *sample)
1970{
1971 print_binary(sample->raw_data, sample->raw_size, 8,
1972 bpf_output__printer, trace->output);
1973}
1974
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001975static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1976 union perf_event *event __maybe_unused,
1977 struct perf_sample *sample)
1978{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001979 int callchain_ret = 0;
1980
1981 if (sample->callchain) {
1982 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1983 if (callchain_ret == 0) {
1984 if (callchain_cursor.nr < trace->min_stack)
1985 goto out;
1986 callchain_ret = 1;
1987 }
1988 }
1989
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001990 trace__printf_interrupted_entry(trace, sample);
1991 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001992
1993 if (trace->trace_syscalls)
1994 fprintf(trace->output, "( ): ");
1995
1996 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001997
Wang Nan1d6c9402016-02-26 09:31:55 +00001998 if (perf_evsel__is_bpf_output(evsel)) {
1999 bpf_output__fprintf(trace, sample);
2000 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002001 event_format__fprintf(evsel->tp_format, sample->cpu,
2002 sample->raw_data, sample->raw_size,
2003 trace->output);
2004 }
2005
2006 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03002007
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002008 if (callchain_ret > 0)
2009 trace__fprintf_callchain(trace, sample);
2010 else if (callchain_ret < 0)
2011 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
2012out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002013 return 0;
2014}
2015
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002016static void print_location(FILE *f, struct perf_sample *sample,
2017 struct addr_location *al,
2018 bool print_dso, bool print_sym)
2019{
2020
2021 if ((verbose || print_dso) && al->map)
2022 fprintf(f, "%s@", al->map->dso->long_name);
2023
2024 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002025 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002026 al->addr - al->sym->start);
2027 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002028 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002029 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002030 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002031}
2032
2033static int trace__pgfault(struct trace *trace,
2034 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002035 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002036 struct perf_sample *sample)
2037{
2038 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002039 struct addr_location al;
2040 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002041 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002042 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002043 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002044
2045 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002046
2047 if (sample->callchain) {
2048 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2049 if (callchain_ret == 0) {
2050 if (callchain_cursor.nr < trace->min_stack)
2051 goto out_put;
2052 callchain_ret = 1;
2053 }
2054 }
2055
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002056 ttrace = thread__trace(thread, trace->output);
2057 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002058 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002059
2060 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2061 ttrace->pfmaj++;
2062 else
2063 ttrace->pfmin++;
2064
2065 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002066 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002067
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002068 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002069 sample->ip, &al);
2070
2071 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2072
2073 fprintf(trace->output, "%sfault [",
2074 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2075 "maj" : "min");
2076
2077 print_location(trace->output, sample, &al, false, true);
2078
2079 fprintf(trace->output, "] => ");
2080
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002081 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002082 sample->addr, &al);
2083
2084 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002085 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002086 MAP__FUNCTION, sample->addr, &al);
2087
2088 if (al.map)
2089 map_type = 'x';
2090 else
2091 map_type = '?';
2092 }
2093
2094 print_location(trace->output, sample, &al, true, false);
2095
2096 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002097
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002098 if (callchain_ret > 0)
2099 trace__fprintf_callchain(trace, sample);
2100 else if (callchain_ret < 0)
2101 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002102out:
2103 err = 0;
2104out_put:
2105 thread__put(thread);
2106 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002107}
2108
David Ahernbdc89662013-08-28 22:29:53 -06002109static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2110{
2111 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2112 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2113 return false;
2114
2115 if (trace->pid_list || trace->tid_list)
2116 return true;
2117
2118 return false;
2119}
2120
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002121static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002122 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002123 struct perf_sample *sample)
2124{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002125 /*
2126 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2127 * and don't use sample->time unconditionally, we may end up having
2128 * some other event in the future without PERF_SAMPLE_TIME for good
2129 * reason, i.e. we may not be interested in its timestamps, just in
2130 * it taking place, picking some piece of information when it
2131 * appears in our event stream (vfs_getname comes to mind).
2132 */
2133 if (trace->base_time == 0 && !trace->full_time &&
2134 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002135 trace->base_time = sample->time;
2136}
2137
David Ahern6810fc92013-08-28 22:29:52 -06002138static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002139 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002140 struct perf_sample *sample,
2141 struct perf_evsel *evsel,
2142 struct machine *machine __maybe_unused)
2143{
2144 struct trace *trace = container_of(tool, struct trace, tool);
2145 int err = 0;
2146
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002147 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002148
David Ahernbdc89662013-08-28 22:29:53 -06002149 if (skip_sample(trace, sample))
2150 return 0;
2151
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002152 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002153
David Ahern31605652013-12-04 19:41:41 -07002154 if (handler) {
2155 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002156 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002157 }
David Ahern6810fc92013-08-28 22:29:52 -06002158
2159 return err;
2160}
2161
David Ahernbdc89662013-08-28 22:29:53 -06002162static int parse_target_str(struct trace *trace)
2163{
2164 if (trace->opts.target.pid) {
2165 trace->pid_list = intlist__new(trace->opts.target.pid);
2166 if (trace->pid_list == NULL) {
2167 pr_err("Error parsing process id string\n");
2168 return -EINVAL;
2169 }
2170 }
2171
2172 if (trace->opts.target.tid) {
2173 trace->tid_list = intlist__new(trace->opts.target.tid);
2174 if (trace->tid_list == NULL) {
2175 pr_err("Error parsing thread id string\n");
2176 return -EINVAL;
2177 }
2178 }
2179
2180 return 0;
2181}
2182
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002183static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002184{
2185 unsigned int rec_argc, i, j;
2186 const char **rec_argv;
2187 const char * const record_args[] = {
2188 "record",
2189 "-R",
2190 "-m", "1024",
2191 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002192 };
2193
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002194 const char * const sc_args[] = { "-e", };
2195 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2196 const char * const majpf_args[] = { "-e", "major-faults" };
2197 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2198 const char * const minpf_args[] = { "-e", "minor-faults" };
2199 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2200
David Ahern9aca7f12013-12-04 19:41:39 -07002201 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002202 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2203 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002204 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2205
2206 if (rec_argv == NULL)
2207 return -ENOMEM;
2208
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002209 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002210 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002211 rec_argv[j++] = record_args[i];
2212
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002213 if (trace->trace_syscalls) {
2214 for (i = 0; i < sc_args_nr; i++)
2215 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002216
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002217 /* event string may be different for older kernels - e.g., RHEL6 */
2218 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2219 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2220 else if (is_valid_tracepoint("syscalls:sys_enter"))
2221 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2222 else {
2223 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2224 return -1;
2225 }
David Ahern9aca7f12013-12-04 19:41:39 -07002226 }
David Ahern9aca7f12013-12-04 19:41:39 -07002227
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002228 if (trace->trace_pgfaults & TRACE_PFMAJ)
2229 for (i = 0; i < majpf_args_nr; i++)
2230 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002231
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002232 if (trace->trace_pgfaults & TRACE_PFMIN)
2233 for (i = 0; i < minpf_args_nr; i++)
2234 rec_argv[j++] = minpf_args[i];
2235
2236 for (i = 0; i < (unsigned int)argc; i++)
2237 rec_argv[j++] = argv[i];
2238
2239 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002240}
2241
David Ahernbf2575c2013-10-08 21:26:53 -06002242static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2243
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002244static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002245{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002246 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002247
2248 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002249 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002250
2251 if (perf_evsel__field(evsel, "pathname") == NULL) {
2252 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002253 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002254 }
2255
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002256 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002257 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002258 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002259}
2260
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002261static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002262{
2263 struct perf_evsel *evsel;
2264 struct perf_event_attr attr = {
2265 .type = PERF_TYPE_SOFTWARE,
2266 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002267 };
2268
2269 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002270 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002271
2272 event_attr_init(&attr);
2273
2274 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002275 if (evsel)
2276 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002277
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002278 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002279}
2280
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002281static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2282{
2283 const u32 type = event->header.type;
2284 struct perf_evsel *evsel;
2285
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002286 if (type != PERF_RECORD_SAMPLE) {
2287 trace__process_event(trace, trace->host, event, sample);
2288 return;
2289 }
2290
2291 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2292 if (evsel == NULL) {
2293 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2294 return;
2295 }
2296
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002297 trace__set_base_time(trace, evsel, sample);
2298
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002299 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2300 sample->raw_data == NULL) {
2301 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2302 perf_evsel__name(evsel), sample->tid,
2303 sample->cpu, sample->raw_size);
2304 } else {
2305 tracepoint_handler handler = evsel->handler;
2306 handler(trace, evsel, event, sample);
2307 }
2308}
2309
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002310static int trace__add_syscall_newtp(struct trace *trace)
2311{
2312 int ret = -1;
2313 struct perf_evlist *evlist = trace->evlist;
2314 struct perf_evsel *sys_enter, *sys_exit;
2315
2316 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2317 if (sys_enter == NULL)
2318 goto out;
2319
2320 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2321 goto out_delete_sys_enter;
2322
2323 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2324 if (sys_exit == NULL)
2325 goto out_delete_sys_enter;
2326
2327 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2328 goto out_delete_sys_exit;
2329
2330 perf_evlist__add(evlist, sys_enter);
2331 perf_evlist__add(evlist, sys_exit);
2332
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002333 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002334 /*
2335 * We're interested only in the user space callchain
2336 * leading to the syscall, allow overriding that for
2337 * debugging reasons using --kernel_syscall_callchains
2338 */
2339 sys_exit->attr.exclude_callchain_kernel = 1;
2340 }
2341
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002342 trace->syscalls.events.sys_enter = sys_enter;
2343 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002344
2345 ret = 0;
2346out:
2347 return ret;
2348
2349out_delete_sys_exit:
2350 perf_evsel__delete_priv(sys_exit);
2351out_delete_sys_enter:
2352 perf_evsel__delete_priv(sys_enter);
2353 goto out;
2354}
2355
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002356static int trace__set_ev_qualifier_filter(struct trace *trace)
2357{
2358 int err = -1;
2359 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2360 trace->ev_qualifier_ids.nr,
2361 trace->ev_qualifier_ids.entries);
2362
2363 if (filter == NULL)
2364 goto out_enomem;
2365
2366 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2367 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2368
2369 free(filter);
2370out:
2371 return err;
2372out_enomem:
2373 errno = ENOMEM;
2374 goto out;
2375}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002376
Namhyung Kimf15eb532012-10-05 14:02:16 +09002377static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002378{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002379 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002380 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002381 int err = -1, i;
2382 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002383 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002384 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002385
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002386 trace->live = true;
2387
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002388 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002389 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002390
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002391 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002392 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002393
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002394 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2395 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2396 if (pgfault_maj == NULL)
2397 goto out_error_mem;
2398 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002399 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002400
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002401 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2402 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2403 if (pgfault_min == NULL)
2404 goto out_error_mem;
2405 perf_evlist__add(evlist, pgfault_min);
2406 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002407
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002408 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002409 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2410 trace__sched_stat_runtime))
2411 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002412
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002413 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2414 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002415 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002416 goto out_delete_evlist;
2417 }
2418
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002419 err = trace__symbols_init(trace, evlist);
2420 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002421 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002422 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002423 }
2424
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002425 perf_evlist__config(evlist, &trace->opts, NULL);
2426
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002427 if (callchain_param.enabled) {
2428 bool use_identifier = false;
2429
2430 if (trace->syscalls.events.sys_exit) {
2431 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2432 &trace->opts, &callchain_param);
2433 use_identifier = true;
2434 }
2435
2436 if (pgfault_maj) {
2437 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2438 use_identifier = true;
2439 }
2440
2441 if (pgfault_min) {
2442 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2443 use_identifier = true;
2444 }
2445
2446 if (use_identifier) {
2447 /*
2448 * Now we have evsels with different sample_ids, use
2449 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2450 * from a fixed position in each ring buffer record.
2451 *
2452 * As of this the changeset introducing this comment, this
2453 * isn't strictly needed, as the fields that can come before
2454 * PERF_SAMPLE_ID are all used, but we'll probably disable
2455 * some of those for things like copying the payload of
2456 * pointer syscall arguments, and for vfs_getname we don't
2457 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2458 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2459 */
2460 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2461 perf_evlist__reset_sample_bit(evlist, ID);
2462 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002463 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002464
Namhyung Kimf15eb532012-10-05 14:02:16 +09002465 signal(SIGCHLD, sig_handler);
2466 signal(SIGINT, sig_handler);
2467
2468 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002469 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002470 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002471 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002472 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002473 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002474 }
2475 }
2476
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002477 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002478 if (err < 0)
2479 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002480
Wang Nanba504232016-02-26 09:31:54 +00002481 err = bpf__apply_obj_config();
2482 if (err) {
2483 char errbuf[BUFSIZ];
2484
2485 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2486 pr_err("ERROR: Apply config to BPF failed: %s\n",
2487 errbuf);
2488 goto out_error_open;
2489 }
2490
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002491 /*
2492 * Better not use !target__has_task() here because we need to cover the
2493 * case where no threads were specified in the command line, but a
2494 * workload was, and in that case we will fill in the thread_map when
2495 * we fork the workload in perf_evlist__prepare_workload.
2496 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002497 if (trace->filter_pids.nr > 0)
2498 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002499 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002500 err = perf_evlist__set_filter_pid(evlist, getpid());
2501
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002502 if (err < 0)
2503 goto out_error_mem;
2504
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002505 if (trace->ev_qualifier_ids.nr > 0) {
2506 err = trace__set_ev_qualifier_filter(trace);
2507 if (err < 0)
2508 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002509
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002510 pr_debug("event qualifier tracepoint filter: %s\n",
2511 trace->syscalls.events.sys_exit->filter);
2512 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002513
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002514 err = perf_evlist__apply_filters(evlist, &evsel);
2515 if (err < 0)
2516 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002517
Jiri Olsaf8850372013-11-28 17:57:22 +01002518 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002519 if (err < 0)
2520 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002521
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002522 if (!target__none(&trace->opts.target))
2523 perf_evlist__enable(evlist);
2524
Namhyung Kimf15eb532012-10-05 14:02:16 +09002525 if (forks)
2526 perf_evlist__start_workload(evlist);
2527
Jiri Olsae13798c2015-06-23 00:36:02 +02002528 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002529 evlist->threads->nr > 1 ||
2530 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002531again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002532 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002533
2534 for (i = 0; i < evlist->nr_mmaps; i++) {
2535 union perf_event *event;
2536
2537 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002538 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002539
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002540 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002541
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002542 err = perf_evlist__parse_sample(evlist, event, &sample);
2543 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002544 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002545 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002546 }
2547
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002548 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002549next_event:
2550 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002551
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002552 if (interrupted)
2553 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002554
2555 if (done && !draining) {
2556 perf_evlist__disable(evlist);
2557 draining = true;
2558 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002559 }
2560 }
2561
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002562 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002563 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002564
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002565 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2566 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2567 draining = true;
2568
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002569 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002570 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002571 } else {
2572 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002573 }
2574
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002575out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002576 thread__zput(trace->current);
2577
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002578 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002579
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002580 if (!err) {
2581 if (trace->summary)
2582 trace__fprintf_thread_summary(trace, trace->output);
2583
2584 if (trace->show_tool_stats) {
2585 fprintf(trace->output, "Stats:\n "
2586 " vfs_getname : %" PRIu64 "\n"
2587 " proc_getname: %" PRIu64 "\n",
2588 trace->stats.vfs_getname,
2589 trace->stats.proc_getname);
2590 }
2591 }
David Ahernbf2575c2013-10-08 21:26:53 -06002592
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002593out_delete_evlist:
2594 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002595 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002596 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002597 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002598{
2599 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002600
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002601out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002602 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002603 goto out_error;
2604
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002605out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002606 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002607 goto out_error;
2608
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002609out_error_mmap:
2610 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2611 goto out_error;
2612
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002613out_error_open:
2614 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2615
2616out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002617 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302618 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002619
2620out_error_apply_filters:
2621 fprintf(trace->output,
2622 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2623 evsel->filter, perf_evsel__name(evsel), errno,
2624 strerror_r(errno, errbuf, sizeof(errbuf)));
2625 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002626}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002627out_error_mem:
2628 fprintf(trace->output, "Not enough memory to run!\n");
2629 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002630
2631out_errno:
2632 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2633 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002634}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002635
David Ahern6810fc92013-08-28 22:29:52 -06002636static int trace__replay(struct trace *trace)
2637{
2638 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002639 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002640 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002641 struct perf_data_file file = {
2642 .path = input_name,
2643 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002644 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002645 };
David Ahern6810fc92013-08-28 22:29:52 -06002646 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002647 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002648 int err = -1;
2649
2650 trace->tool.sample = trace__process_sample;
2651 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002652 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002653 trace->tool.comm = perf_event__process_comm;
2654 trace->tool.exit = perf_event__process_exit;
2655 trace->tool.fork = perf_event__process_fork;
2656 trace->tool.attr = perf_event__process_attr;
2657 trace->tool.tracing_data = perf_event__process_tracing_data;
2658 trace->tool.build_id = perf_event__process_build_id;
2659
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002660 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002661 trace->tool.ordering_requires_timestamps = true;
2662
2663 /* add tid to output */
2664 trace->multiple_threads = true;
2665
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002666 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002667 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002668 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002669
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002670 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002671 goto out;
2672
David Ahern8fb598e2013-09-28 13:13:00 -06002673 trace->host = &session->machines.host;
2674
David Ahern6810fc92013-08-28 22:29:52 -06002675 err = perf_session__set_tracepoints_handlers(session, handlers);
2676 if (err)
2677 goto out;
2678
Namhyung Kim003824e2013-11-12 15:25:00 +09002679 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2680 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002681 /* older kernels have syscalls tp versus raw_syscalls */
2682 if (evsel == NULL)
2683 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2684 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002685
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002686 if (evsel &&
2687 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2688 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002689 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2690 goto out;
2691 }
2692
2693 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2694 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002695 if (evsel == NULL)
2696 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2697 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002698 if (evsel &&
2699 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2700 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002701 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002702 goto out;
2703 }
2704
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002705 evlist__for_each(session->evlist, evsel) {
2706 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2707 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2708 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2709 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2710 evsel->handler = trace__pgfault;
2711 }
2712
David Ahernbdc89662013-08-28 22:29:53 -06002713 err = parse_target_str(trace);
2714 if (err != 0)
2715 goto out;
2716
David Ahern6810fc92013-08-28 22:29:52 -06002717 setup_pager();
2718
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002719 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002720 if (err)
2721 pr_err("Failed to process events, error %d", err);
2722
David Ahernbf2575c2013-10-08 21:26:53 -06002723 else if (trace->summary)
2724 trace__fprintf_thread_summary(trace, trace->output);
2725
David Ahern6810fc92013-08-28 22:29:52 -06002726out:
2727 perf_session__delete(session);
2728
2729 return err;
2730}
2731
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002732static size_t trace__fprintf_threads_header(FILE *fp)
2733{
2734 size_t printed;
2735
Pekka Enberg99ff7152013-11-12 16:42:14 +02002736 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002737
2738 return printed;
2739}
2740
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002741DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2742 struct stats *stats;
2743 double msecs;
2744 int syscall;
2745)
2746{
2747 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2748 struct stats *stats = source->priv;
2749
2750 entry->syscall = source->i;
2751 entry->stats = stats;
2752 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2753}
2754
David Ahernbf2575c2013-10-08 21:26:53 -06002755static size_t thread__dump_stats(struct thread_trace *ttrace,
2756 struct trace *trace, FILE *fp)
2757{
David Ahernbf2575c2013-10-08 21:26:53 -06002758 size_t printed = 0;
2759 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002760 struct rb_node *nd;
2761 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002762
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002763 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002764 return 0;
2765
2766 printed += fprintf(fp, "\n");
2767
Milian Wolff834fd462015-08-06 11:24:29 +02002768 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2769 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2770 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002771
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002772 resort_rb__for_each(nd, syscall_stats) {
2773 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002774 if (stats) {
2775 double min = (double)(stats->min) / NSEC_PER_MSEC;
2776 double max = (double)(stats->max) / NSEC_PER_MSEC;
2777 double avg = avg_stats(stats);
2778 double pct;
2779 u64 n = (u64) stats->n;
2780
2781 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2782 avg /= NSEC_PER_MSEC;
2783
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002784 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002785 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002786 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002787 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002788 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002789 }
David Ahernbf2575c2013-10-08 21:26:53 -06002790 }
2791
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002792 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002793 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002794
2795 return printed;
2796}
2797
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002798static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002799{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002800 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002801 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002802 double ratio;
2803
2804 if (ttrace == NULL)
2805 return 0;
2806
2807 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2808
Pekka Enberg15e65c62013-11-14 18:43:30 +02002809 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002810 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002811 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002812 if (ttrace->pfmaj)
2813 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2814 if (ttrace->pfmin)
2815 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002816 if (trace->sched)
2817 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2818 else if (fputc('\n', fp) != EOF)
2819 ++printed;
2820
David Ahernbf2575c2013-10-08 21:26:53 -06002821 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002822
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002823 return printed;
2824}
David Ahern896cbb52013-09-28 13:12:59 -06002825
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002826static unsigned long thread__nr_events(struct thread_trace *ttrace)
2827{
2828 return ttrace ? ttrace->nr_events : 0;
2829}
2830
2831DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2832 struct thread *thread;
2833)
2834{
2835 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002836}
2837
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002838static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2839{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002840 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2841 size_t printed = trace__fprintf_threads_header(fp);
2842 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002843
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002844 if (threads == NULL) {
2845 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2846 return 0;
2847 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002848
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002849 resort_rb__for_each(nd, threads)
2850 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2851
2852 resort_rb__delete(threads);
2853
2854 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002855}
2856
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002857static int trace__set_duration(const struct option *opt, const char *str,
2858 int unset __maybe_unused)
2859{
2860 struct trace *trace = opt->value;
2861
2862 trace->duration_filter = atof(str);
2863 return 0;
2864}
2865
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002866static int trace__set_filter_pids(const struct option *opt, const char *str,
2867 int unset __maybe_unused)
2868{
2869 int ret = -1;
2870 size_t i;
2871 struct trace *trace = opt->value;
2872 /*
2873 * FIXME: introduce a intarray class, plain parse csv and create a
2874 * { int nr, int entries[] } struct...
2875 */
2876 struct intlist *list = intlist__new(str);
2877
2878 if (list == NULL)
2879 return -1;
2880
2881 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2882 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2883
2884 if (trace->filter_pids.entries == NULL)
2885 goto out;
2886
2887 trace->filter_pids.entries[0] = getpid();
2888
2889 for (i = 1; i < trace->filter_pids.nr; ++i)
2890 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2891
2892 intlist__delete(list);
2893 ret = 0;
2894out:
2895 return ret;
2896}
2897
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002898static int trace__open_output(struct trace *trace, const char *filename)
2899{
2900 struct stat st;
2901
2902 if (!stat(filename, &st) && st.st_size) {
2903 char oldname[PATH_MAX];
2904
2905 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2906 unlink(oldname);
2907 rename(filename, oldname);
2908 }
2909
2910 trace->output = fopen(filename, "w");
2911
2912 return trace->output == NULL ? -errno : 0;
2913}
2914
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002915static int parse_pagefaults(const struct option *opt, const char *str,
2916 int unset __maybe_unused)
2917{
2918 int *trace_pgfaults = opt->value;
2919
2920 if (strcmp(str, "all") == 0)
2921 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2922 else if (strcmp(str, "maj") == 0)
2923 *trace_pgfaults |= TRACE_PFMAJ;
2924 else if (strcmp(str, "min") == 0)
2925 *trace_pgfaults |= TRACE_PFMIN;
2926 else
2927 return -1;
2928
2929 return 0;
2930}
2931
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002932static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2933{
2934 struct perf_evsel *evsel;
2935
2936 evlist__for_each(evlist, evsel)
2937 evsel->handler = handler;
2938}
2939
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002940int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2941{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002942 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002943 "perf trace [<options>] [<command>]",
2944 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002945 "perf trace record [<options>] [<command>]",
2946 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002947 NULL
2948 };
2949 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002950 .syscalls = {
2951 . max = -1,
2952 },
2953 .opts = {
2954 .target = {
2955 .uid = UINT_MAX,
2956 .uses_mmap = true,
2957 },
2958 .user_freq = UINT_MAX,
2959 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002960 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002961 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002962 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002963 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002964 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002965 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002966 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002967 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002968 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002969 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002970 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002971 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002972 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002973 OPT_CALLBACK(0, "event", &trace.evlist, "event",
2974 "event selector. use 'perf list' to list available events",
2975 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002976 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2977 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002978 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03002979 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002980 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002981 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002982 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2983 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002984 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002985 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002986 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2987 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002988 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002989 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002990 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002991 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002992 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002993 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002994 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2995 "number of mmap data pages",
2996 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002997 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002998 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002999 OPT_CALLBACK(0, "duration", &trace, "float",
3000 "show only events with duration > N.M ms",
3001 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003002 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003003 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003004 OPT_BOOLEAN('T', "time", &trace.full_time,
3005 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003006 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3007 "Show only syscall summary with statistics"),
3008 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3009 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003010 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3011 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003012 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003013 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003014 OPT_CALLBACK(0, "call-graph", &trace.opts,
3015 "record_mode[,record_size]", record_callchain_help,
3016 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003017 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3018 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03003019 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3020 "Set the minimum stack depth when parsing the callchain, "
3021 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03003022 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3023 "Set the maximum stack depth when parsing the callchain, "
3024 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03003025 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04003026 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3027 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003028 OPT_END()
3029 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003030 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003031 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003032 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003033 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003034 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003035
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003036 signal(SIGSEGV, sighandler_dump_stack);
3037 signal(SIGFPE, sighandler_dump_stack);
3038
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003039 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003040 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003041
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003042 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003043 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003044 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003045 goto out;
3046 }
3047
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003048 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3049 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003050
Wang Nand7888572016-04-08 15:07:24 +00003051 err = bpf__setup_stdout(trace.evlist);
3052 if (err) {
3053 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3054 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3055 goto out;
3056 }
3057
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003058 err = -1;
3059
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003060 if (trace.trace_pgfaults) {
3061 trace.opts.sample_address = true;
3062 trace.opts.sample_time = true;
3063 }
3064
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003065 if (trace.opts.mmap_pages == UINT_MAX)
3066 mmap_pages_user_set = false;
3067
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003068 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03003069 trace.max_stack = sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003070 max_stack_user_set = false;
3071 }
3072
3073#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003074 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003075 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
3076#endif
3077
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003078 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003079 if (!mmap_pages_user_set && geteuid() == 0)
3080 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3081
Milian Wolff566a0882016-04-08 13:34:15 +02003082 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003083 }
Milian Wolff566a0882016-04-08 13:34:15 +02003084
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003085 if (trace.evlist->nr_entries > 0)
3086 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3087
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003088 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3089 return trace__record(&trace, argc-1, &argv[1]);
3090
3091 /* summary_only implies summary option, but don't overwrite summary if set */
3092 if (trace.summary_only)
3093 trace.summary = trace.summary_only;
3094
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003095 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3096 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003097 pr_err("Please specify something to trace.\n");
3098 return -1;
3099 }
3100
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003101 if (!trace.trace_syscalls && ev_qualifier_str) {
3102 pr_err("The -e option can't be used with --no-syscalls.\n");
3103 goto out;
3104 }
3105
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003106 if (output_name != NULL) {
3107 err = trace__open_output(&trace, output_name);
3108 if (err < 0) {
3109 perror("failed to create output file");
3110 goto out;
3111 }
3112 }
3113
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003114 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3115
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003116 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003117 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003118 struct strlist_config slist_config = {
3119 .dirname = system_path(STRACE_GROUPS_DIR),
3120 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003121
3122 trace.not_ev_qualifier = *s == '!';
3123 if (trace.not_ev_qualifier)
3124 ++s;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003125 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003126 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003127 fputs("Not enough memory to parse event qualifier",
3128 trace.output);
3129 err = -ENOMEM;
3130 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003131 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003132
3133 err = trace__validate_ev_qualifier(&trace);
3134 if (err)
3135 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003136 }
3137
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003138 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003139 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003140 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003141 fprintf(trace.output, "%s", bf);
3142 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003143 }
3144
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003145 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003146 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003147 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003148 fprintf(trace.output, "%s", bf);
3149 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003150 }
3151
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003152 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003153 trace.opts.target.system_wide = true;
3154
David Ahern6810fc92013-08-28 22:29:52 -06003155 if (input_name)
3156 err = trace__replay(&trace);
3157 else
3158 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003159
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003160out_close:
3161 if (output_name != NULL)
3162 fclose(trace.output);
3163out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003164 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003165}