blob: 903deda92d9e8ef7fc2515b8660c55a25f7559b9 [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 Melo514f1c62012-09-26 20:05:56 -030039
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030040#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030041#include <stdlib.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030042#include <linux/futex.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020043#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030044#include <linux/seccomp.h>
45#include <linux/filter.h>
46#include <linux/audit.h>
47#include <sys/ptrace.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030048#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030049#include <linux/stringify.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030050
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030051#ifndef O_CLOEXEC
52# define O_CLOEXEC 02000000
53#endif
54
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030055#ifndef MSG_CMSG_CLOEXEC
56# define MSG_CMSG_CLOEXEC 0x40000000
57#endif
58
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030059struct trace {
60 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030061 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030062 struct {
63 int max;
64 struct syscall *table;
65 struct {
66 struct perf_evsel *sys_enter,
67 *sys_exit;
68 } events;
69 } syscalls;
70 struct record_opts opts;
71 struct perf_evlist *evlist;
72 struct machine *host;
73 struct thread *current;
74 u64 base_time;
75 FILE *output;
76 unsigned long nr_events;
77 struct strlist *ev_qualifier;
78 struct {
79 size_t nr;
80 int *entries;
81 } ev_qualifier_ids;
82 struct intlist *tid_list;
83 struct intlist *pid_list;
84 struct {
85 size_t nr;
86 pid_t *entries;
87 } filter_pids;
88 double duration_filter;
89 double runtime_ms;
90 struct {
91 u64 vfs_getname,
92 proc_getname;
93 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030094 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -030095 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030096 bool not_ev_qualifier;
97 bool live;
98 bool full_time;
99 bool sched;
100 bool multiple_threads;
101 bool summary;
102 bool summary_only;
103 bool show_comm;
104 bool show_tool_stats;
105 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300106 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300107 bool force;
108 bool vfs_getname;
109 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300110 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300111};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300112
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300113struct tp_field {
114 int offset;
115 union {
116 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
117 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
118 };
119};
120
121#define TP_UINT_FIELD(bits) \
122static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
123{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500124 u##bits value; \
125 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
126 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300127}
128
129TP_UINT_FIELD(8);
130TP_UINT_FIELD(16);
131TP_UINT_FIELD(32);
132TP_UINT_FIELD(64);
133
134#define TP_UINT_FIELD__SWAPPED(bits) \
135static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
136{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500137 u##bits value; \
138 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300139 return bswap_##bits(value);\
140}
141
142TP_UINT_FIELD__SWAPPED(16);
143TP_UINT_FIELD__SWAPPED(32);
144TP_UINT_FIELD__SWAPPED(64);
145
146static int tp_field__init_uint(struct tp_field *field,
147 struct format_field *format_field,
148 bool needs_swap)
149{
150 field->offset = format_field->offset;
151
152 switch (format_field->size) {
153 case 1:
154 field->integer = tp_field__u8;
155 break;
156 case 2:
157 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
158 break;
159 case 4:
160 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
161 break;
162 case 8:
163 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
164 break;
165 default:
166 return -1;
167 }
168
169 return 0;
170}
171
172static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
173{
174 return sample->raw_data + field->offset;
175}
176
177static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
178{
179 field->offset = format_field->offset;
180 field->pointer = tp_field__ptr;
181 return 0;
182}
183
184struct syscall_tp {
185 struct tp_field id;
186 union {
187 struct tp_field args, ret;
188 };
189};
190
191static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
192 struct tp_field *field,
193 const char *name)
194{
195 struct format_field *format_field = perf_evsel__field(evsel, name);
196
197 if (format_field == NULL)
198 return -1;
199
200 return tp_field__init_uint(field, format_field, evsel->needs_swap);
201}
202
203#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
204 ({ struct syscall_tp *sc = evsel->priv;\
205 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
206
207static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
208 struct tp_field *field,
209 const char *name)
210{
211 struct format_field *format_field = perf_evsel__field(evsel, name);
212
213 if (format_field == NULL)
214 return -1;
215
216 return tp_field__init_ptr(field, format_field);
217}
218
219#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
220 ({ struct syscall_tp *sc = evsel->priv;\
221 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
222
223static void perf_evsel__delete_priv(struct perf_evsel *evsel)
224{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300225 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300226 perf_evsel__delete(evsel);
227}
228
Namhyung Kim96695d42013-11-12 08:51:45 -0300229static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
230{
231 evsel->priv = malloc(sizeof(struct syscall_tp));
232 if (evsel->priv != NULL) {
233 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
234 goto out_delete;
235
236 evsel->handler = handler;
237 return 0;
238 }
239
240 return -ENOMEM;
241
242out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300243 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300244 return -ENOENT;
245}
246
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300247static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300248{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300249 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300250
David Ahern9aca7f12013-12-04 19:41:39 -0700251 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200252 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700253 evsel = perf_evsel__newtp("syscalls", direction);
254
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200255 if (IS_ERR(evsel))
256 return NULL;
257
258 if (perf_evsel__init_syscall_tp(evsel, handler))
259 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300260
261 return evsel;
262
263out_delete:
264 perf_evsel__delete_priv(evsel);
265 return NULL;
266}
267
268#define perf_evsel__sc_tp_uint(evsel, name, sample) \
269 ({ struct syscall_tp *fields = evsel->priv; \
270 fields->name.integer(&fields->name, sample); })
271
272#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
273 ({ struct syscall_tp *fields = evsel->priv; \
274 fields->name.pointer(&fields->name, sample); })
275
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300276struct syscall_arg {
277 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300278 struct thread *thread;
279 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300280 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300281 u8 idx;
282 u8 mask;
283};
284
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300285struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300286 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300287 int nr_entries;
288 const char **entries;
289};
290
291#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
292 .nr_entries = ARRAY_SIZE(array), \
293 .entries = array, \
294}
295
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300296#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
297 .offset = off, \
298 .nr_entries = ARRAY_SIZE(array), \
299 .entries = array, \
300}
301
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300302static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
303 const char *intfmt,
304 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300305{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300306 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300307 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300308
309 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300310 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300311
312 return scnprintf(bf, size, "%s", sa->entries[idx]);
313}
314
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300315static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
316 struct syscall_arg *arg)
317{
318 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
319}
320
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300321#define SCA_STRARRAY syscall_arg__scnprintf_strarray
322
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300323#if defined(__i386__) || defined(__x86_64__)
324/*
325 * FIXME: Make this available to all arches as soon as the ioctl beautifier
326 * gets rewritten to support all arches.
327 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300328static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
329 struct syscall_arg *arg)
330{
331 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
332}
333
334#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300335#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300336
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300337static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
338 struct syscall_arg *arg);
339
340#define SCA_FD syscall_arg__scnprintf_fd
341
342static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
343 struct syscall_arg *arg)
344{
345 int fd = arg->val;
346
347 if (fd == AT_FDCWD)
348 return scnprintf(bf, size, "CWD");
349
350 return syscall_arg__scnprintf_fd(bf, size, arg);
351}
352
353#define SCA_FDAT syscall_arg__scnprintf_fd_at
354
355static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
356 struct syscall_arg *arg);
357
358#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
359
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300360static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300361 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300362{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300363 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300364}
365
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300366#define SCA_HEX syscall_arg__scnprintf_hex
367
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300368static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
369 struct syscall_arg *arg)
370{
371 return scnprintf(bf, size, "%d", arg->val);
372}
373
374#define SCA_INT syscall_arg__scnprintf_int
375
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300376static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
377 struct syscall_arg *arg)
378{
379 int printed = 0, op = arg->val;
380
381 if (op == 0)
382 return scnprintf(bf, size, "NONE");
383#define P_CMD(cmd) \
384 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
385 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
386 op &= ~LOCK_##cmd; \
387 }
388
389 P_CMD(SH);
390 P_CMD(EX);
391 P_CMD(NB);
392 P_CMD(UN);
393 P_CMD(MAND);
394 P_CMD(RW);
395 P_CMD(READ);
396 P_CMD(WRITE);
397#undef P_OP
398
399 if (op)
400 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
401
402 return printed;
403}
404
405#define SCA_FLOCK syscall_arg__scnprintf_flock
406
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300407static 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 -0300408{
409 enum syscall_futex_args {
410 SCF_UADDR = (1 << 0),
411 SCF_OP = (1 << 1),
412 SCF_VAL = (1 << 2),
413 SCF_TIMEOUT = (1 << 3),
414 SCF_UADDR2 = (1 << 4),
415 SCF_VAL3 = (1 << 5),
416 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300417 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300418 int cmd = op & FUTEX_CMD_MASK;
419 size_t printed = 0;
420
421 switch (cmd) {
422#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300423 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
424 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
425 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
426 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
427 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
428 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300429 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300430 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
431 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
432 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
433 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
434 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300435 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
436 default: printed = scnprintf(bf, size, "%#x", cmd); break;
437 }
438
439 if (op & FUTEX_PRIVATE_FLAG)
440 printed += scnprintf(bf + printed, size - printed, "|PRIV");
441
442 if (op & FUTEX_CLOCK_REALTIME)
443 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
444
445 return printed;
446}
447
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300448#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
449
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300450static const char *bpf_cmd[] = {
451 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
452 "MAP_GET_NEXT_KEY", "PROG_LOAD",
453};
454static DEFINE_STRARRAY(bpf_cmd);
455
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300456static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
457static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300458
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300459static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
460static DEFINE_STRARRAY(itimers);
461
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300462static const char *keyctl_options[] = {
463 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
464 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
465 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
466 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
467 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
468};
469static DEFINE_STRARRAY(keyctl_options);
470
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300471static const char *whences[] = { "SET", "CUR", "END",
472#ifdef SEEK_DATA
473"DATA",
474#endif
475#ifdef SEEK_HOLE
476"HOLE",
477#endif
478};
479static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300480
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300481static const char *fcntl_cmds[] = {
482 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
483 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
484 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
485 "F_GETOWNER_UIDS",
486};
487static DEFINE_STRARRAY(fcntl_cmds);
488
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300489static const char *rlimit_resources[] = {
490 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
491 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
492 "RTTIME",
493};
494static DEFINE_STRARRAY(rlimit_resources);
495
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300496static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
497static DEFINE_STRARRAY(sighow);
498
David Ahern4f8c1b72013-09-22 19:45:00 -0600499static const char *clockid[] = {
500 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300501 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
502 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600503};
504static DEFINE_STRARRAY(clockid);
505
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300506static const char *socket_families[] = {
507 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
508 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
509 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
510 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
511 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
512 "ALG", "NFC", "VSOCK",
513};
514static DEFINE_STRARRAY(socket_families);
515
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300516#ifndef MSG_PROBE
517#define MSG_PROBE 0x10
518#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600519#ifndef MSG_WAITFORONE
520#define MSG_WAITFORONE 0x10000
521#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300522#ifndef MSG_SENDPAGE_NOTLAST
523#define MSG_SENDPAGE_NOTLAST 0x20000
524#endif
525#ifndef MSG_FASTOPEN
526#define MSG_FASTOPEN 0x20000000
527#endif
528
529static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
530 struct syscall_arg *arg)
531{
532 int printed = 0, flags = arg->val;
533
534 if (flags == 0)
535 return scnprintf(bf, size, "NONE");
536#define P_MSG_FLAG(n) \
537 if (flags & MSG_##n) { \
538 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
539 flags &= ~MSG_##n; \
540 }
541
542 P_MSG_FLAG(OOB);
543 P_MSG_FLAG(PEEK);
544 P_MSG_FLAG(DONTROUTE);
545 P_MSG_FLAG(TRYHARD);
546 P_MSG_FLAG(CTRUNC);
547 P_MSG_FLAG(PROBE);
548 P_MSG_FLAG(TRUNC);
549 P_MSG_FLAG(DONTWAIT);
550 P_MSG_FLAG(EOR);
551 P_MSG_FLAG(WAITALL);
552 P_MSG_FLAG(FIN);
553 P_MSG_FLAG(SYN);
554 P_MSG_FLAG(CONFIRM);
555 P_MSG_FLAG(RST);
556 P_MSG_FLAG(ERRQUEUE);
557 P_MSG_FLAG(NOSIGNAL);
558 P_MSG_FLAG(MORE);
559 P_MSG_FLAG(WAITFORONE);
560 P_MSG_FLAG(SENDPAGE_NOTLAST);
561 P_MSG_FLAG(FASTOPEN);
562 P_MSG_FLAG(CMSG_CLOEXEC);
563#undef P_MSG_FLAG
564
565 if (flags)
566 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
567
568 return printed;
569}
570
571#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
572
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300573static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
574 struct syscall_arg *arg)
575{
576 size_t printed = 0;
577 int mode = arg->val;
578
579 if (mode == F_OK) /* 0 */
580 return scnprintf(bf, size, "F");
581#define P_MODE(n) \
582 if (mode & n##_OK) { \
583 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
584 mode &= ~n##_OK; \
585 }
586
587 P_MODE(R);
588 P_MODE(W);
589 P_MODE(X);
590#undef P_MODE
591
592 if (mode)
593 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
594
595 return printed;
596}
597
598#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
599
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300600static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
601 struct syscall_arg *arg);
602
603#define SCA_FILENAME syscall_arg__scnprintf_filename
604
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300605static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300606 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300607{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300608 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300609
610 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300611 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300612
613 if (flags == 0)
614 return scnprintf(bf, size, "RDONLY");
615#define P_FLAG(n) \
616 if (flags & O_##n) { \
617 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
618 flags &= ~O_##n; \
619 }
620
621 P_FLAG(APPEND);
622 P_FLAG(ASYNC);
623 P_FLAG(CLOEXEC);
624 P_FLAG(CREAT);
625 P_FLAG(DIRECT);
626 P_FLAG(DIRECTORY);
627 P_FLAG(EXCL);
628 P_FLAG(LARGEFILE);
629 P_FLAG(NOATIME);
630 P_FLAG(NOCTTY);
631#ifdef O_NONBLOCK
632 P_FLAG(NONBLOCK);
633#elif O_NDELAY
634 P_FLAG(NDELAY);
635#endif
636#ifdef O_PATH
637 P_FLAG(PATH);
638#endif
639 P_FLAG(RDWR);
640#ifdef O_DSYNC
641 if ((flags & O_SYNC) == O_SYNC)
642 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
643 else {
644 P_FLAG(DSYNC);
645 }
646#else
647 P_FLAG(SYNC);
648#endif
649 P_FLAG(TRUNC);
650 P_FLAG(WRONLY);
651#undef P_FLAG
652
653 if (flags)
654 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
655
656 return printed;
657}
658
659#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
660
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300661static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
662 struct syscall_arg *arg)
663{
664 int printed = 0, flags = arg->val;
665
666#define P_FLAG(n) \
667 if (flags & O_##n) { \
668 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
669 flags &= ~O_##n; \
670 }
671
672 P_FLAG(CLOEXEC);
673 P_FLAG(NONBLOCK);
674#undef P_FLAG
675
676 if (flags)
677 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
678
679 return printed;
680}
681
682#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
683
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300684static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
685{
686 int sig = arg->val;
687
688 switch (sig) {
689#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
690 P_SIGNUM(HUP);
691 P_SIGNUM(INT);
692 P_SIGNUM(QUIT);
693 P_SIGNUM(ILL);
694 P_SIGNUM(TRAP);
695 P_SIGNUM(ABRT);
696 P_SIGNUM(BUS);
697 P_SIGNUM(FPE);
698 P_SIGNUM(KILL);
699 P_SIGNUM(USR1);
700 P_SIGNUM(SEGV);
701 P_SIGNUM(USR2);
702 P_SIGNUM(PIPE);
703 P_SIGNUM(ALRM);
704 P_SIGNUM(TERM);
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300705 P_SIGNUM(CHLD);
706 P_SIGNUM(CONT);
707 P_SIGNUM(STOP);
708 P_SIGNUM(TSTP);
709 P_SIGNUM(TTIN);
710 P_SIGNUM(TTOU);
711 P_SIGNUM(URG);
712 P_SIGNUM(XCPU);
713 P_SIGNUM(XFSZ);
714 P_SIGNUM(VTALRM);
715 P_SIGNUM(PROF);
716 P_SIGNUM(WINCH);
717 P_SIGNUM(IO);
718 P_SIGNUM(PWR);
719 P_SIGNUM(SYS);
Ben Hutchings02c5bb42014-02-06 01:00:41 +0000720#ifdef SIGEMT
721 P_SIGNUM(EMT);
722#endif
723#ifdef SIGSTKFLT
724 P_SIGNUM(STKFLT);
725#endif
726#ifdef SIGSWI
727 P_SIGNUM(SWI);
728#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300729 default: break;
730 }
731
732 return scnprintf(bf, size, "%#x", sig);
733}
734
735#define SCA_SIGNUM syscall_arg__scnprintf_signum
736
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300737#if defined(__i386__) || defined(__x86_64__)
738/*
739 * FIXME: Make this available to all arches.
740 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300741#define TCGETS 0x5401
742
743static const char *tioctls[] = {
744 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
745 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
746 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
747 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
748 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
749 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
750 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
751 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
752 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
753 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
754 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
755 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
756 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
757 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
758 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
759};
760
761static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300762#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300763
Arnaldo Carvalho de Melo6fb35b92016-04-13 11:50:23 -0300764#ifndef SECCOMP_SET_MODE_STRICT
765#define SECCOMP_SET_MODE_STRICT 0
766#endif
767#ifndef SECCOMP_SET_MODE_FILTER
768#define SECCOMP_SET_MODE_FILTER 1
769#endif
770
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300771static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg)
772{
773 int op = arg->val;
774 size_t printed = 0;
775
776 switch (op) {
777#define P_SECCOMP_SET_MODE_OP(n) case SECCOMP_SET_MODE_##n: printed = scnprintf(bf, size, #n); break
778 P_SECCOMP_SET_MODE_OP(STRICT);
779 P_SECCOMP_SET_MODE_OP(FILTER);
780#undef P_SECCOMP_SET_MODE_OP
781 default: printed = scnprintf(bf, size, "%#x", op); break;
782 }
783
784 return printed;
785}
786
787#define SCA_SECCOMP_OP syscall_arg__scnprintf_seccomp_op
788
Arnaldo Carvalho de Melo6fb35b92016-04-13 11:50:23 -0300789#ifndef SECCOMP_FILTER_FLAG_TSYNC
790#define SECCOMP_FILTER_FLAG_TSYNC 1
791#endif
792
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300793static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size,
794 struct syscall_arg *arg)
795{
796 int printed = 0, flags = arg->val;
797
798#define P_FLAG(n) \
799 if (flags & SECCOMP_FILTER_FLAG_##n) { \
800 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
801 flags &= ~SECCOMP_FILTER_FLAG_##n; \
802 }
803
804 P_FLAG(TSYNC);
805#undef P_FLAG
806
807 if (flags)
808 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
809
810 return printed;
811}
812
813#define SCA_SECCOMP_FLAGS syscall_arg__scnprintf_seccomp_flags
814
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300815#ifndef GRND_NONBLOCK
816#define GRND_NONBLOCK 0x0001
817#endif
818#ifndef GRND_RANDOM
819#define GRND_RANDOM 0x0002
820#endif
821
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300822static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
823 struct syscall_arg *arg)
824{
825 int printed = 0, flags = arg->val;
826
827#define P_FLAG(n) \
828 if (flags & GRND_##n) { \
829 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
830 flags &= ~GRND_##n; \
831 }
832
833 P_FLAG(RANDOM);
834 P_FLAG(NONBLOCK);
835#undef P_FLAG
836
837 if (flags)
838 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
839
840 return printed;
841}
842
843#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
844
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300845#define STRARRAY(arg, name, array) \
846 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
847 .arg_parm = { [arg] = &strarray__##array, }
848
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300849#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300850#include "trace/beauty/pid.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300851#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300852#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300853#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300854#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300855#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300856#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300857
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300858static struct syscall_fmt {
859 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300860 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300861 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300862 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300863 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300864 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300865 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300866 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300867} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300868 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300869 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
870 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300871 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300872 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300873 { .name = "brk", .hexret = true,
874 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300875 { .name = "chdir", .errmsg = true,
876 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
877 { .name = "chmod", .errmsg = true,
878 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
879 { .name = "chroot", .errmsg = true,
880 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600881 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300882 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300883 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300884 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300885 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300886 { .name = "creat", .errmsg = true,
887 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300888 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300889 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300890 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300891 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300892 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300893 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300894 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300895 { .name = "eventfd2", .errmsg = true,
896 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300897 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300898 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
899 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300900 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300901 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300902 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300903 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300904 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300905 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300906 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300907 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300908 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300909 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
910 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300911 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300912 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300913 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300914 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
915 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300916 { .name = "fcntl", .errmsg = true,
917 .arg_scnprintf = { [0] = SCA_FD, /* fd */
918 [1] = SCA_STRARRAY, /* cmd */ },
919 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
920 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300921 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300922 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300923 .arg_scnprintf = { [0] = SCA_FD, /* fd */
924 [1] = SCA_FLOCK, /* cmd */ }, },
925 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300926 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300927 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300928 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300929 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300930 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
931 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300932 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300933 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300934 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300935 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300936 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300937 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300938 { .name = "futex", .errmsg = true,
939 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300940 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300941 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
942 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300943 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300944 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300945 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300946 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300947 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300948 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300949 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300950 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300951 { .name = "getrandom", .errmsg = true,
952 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300953 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300954 { .name = "getxattr", .errmsg = true,
955 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
956 { .name = "inotify_add_watch", .errmsg = true,
957 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300958 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300959 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300960#if defined(__i386__) || defined(__x86_64__)
961/*
962 * FIXME: Make this available to all arches.
963 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300964 [1] = SCA_STRHEXARRAY, /* cmd */
965 [2] = SCA_HEX, /* arg */ },
966 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300967#else
968 [2] = SCA_HEX, /* arg */ }, },
969#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300970 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300971 { .name = "kill", .errmsg = true,
972 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300973 { .name = "lchown", .errmsg = true,
974 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
975 { .name = "lgetxattr", .errmsg = true,
976 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300977 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300978 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300979 { .name = "listxattr", .errmsg = true,
980 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300981 { .name = "llistxattr", .errmsg = true,
982 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
983 { .name = "lremovexattr", .errmsg = true,
984 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300985 { .name = "lseek", .errmsg = true,
986 .arg_scnprintf = { [0] = SCA_FD, /* fd */
987 [2] = SCA_STRARRAY, /* whence */ },
988 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300989 { .name = "lsetxattr", .errmsg = true,
990 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300991 { .name = "lstat", .errmsg = true, .alias = "newlstat",
992 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300993 { .name = "lsxattr", .errmsg = true,
994 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300995 { .name = "madvise", .errmsg = true,
996 .arg_scnprintf = { [0] = SCA_HEX, /* start */
997 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300998 { .name = "mkdir", .errmsg = true,
999 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001000 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001001 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1002 [1] = SCA_FILENAME, /* pathname */ }, },
1003 { .name = "mknod", .errmsg = true,
1004 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001005 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001006 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1007 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001008 { .name = "mlock", .errmsg = true,
1009 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1010 { .name = "mlockall", .errmsg = true,
1011 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001012 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001013 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001014 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001015 [3] = SCA_MMAP_FLAGS, /* flags */
1016 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001017 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001018 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1019 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001020 { .name = "mq_unlink", .errmsg = true,
1021 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001022 { .name = "mremap", .hexret = true,
1023 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001024 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001025 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001026 { .name = "munlock", .errmsg = true,
1027 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001028 { .name = "munmap", .errmsg = true,
1029 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001030 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001031 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001032 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001033 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1034 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001035 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001036 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1037 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001038 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001039 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1040 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001041 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001042 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001043 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001044 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001045 { .name = "perf_event_open", .errmsg = true,
1046 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1047 [2] = SCA_INT, /* cpu */
1048 [3] = SCA_FD, /* group_fd */
1049 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001050 { .name = "pipe2", .errmsg = true,
1051 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001052 { .name = "poll", .errmsg = true, .timeout = true, },
1053 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001054 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001055 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001056 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001057 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001058 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001059 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001060 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001061 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001062 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001063 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001064 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001065 { .name = "readlink", .errmsg = true,
1066 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001067 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001068 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1069 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001070 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001071 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001072 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001073 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1074 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001075 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001076 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1077 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001078 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001079 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1080 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001081 { .name = "removexattr", .errmsg = true,
1082 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001083 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001084 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001085 { .name = "rmdir", .errmsg = true,
1086 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001087 { .name = "rt_sigaction", .errmsg = true,
1088 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001089 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001090 { .name = "rt_sigqueueinfo", .errmsg = true,
1091 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1092 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1093 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001094 { .name = "sched_setscheduler", .errmsg = true,
1095 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001096 { .name = "seccomp", .errmsg = true,
1097 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
1098 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001099 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001100 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001101 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1102 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001103 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001104 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1105 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001106 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001107 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1108 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001109 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001110 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001111 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001112 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001113 { .name = "setxattr", .errmsg = true,
1114 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001115 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001116 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001117 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001118 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1119 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001120 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001121 { .name = "socketpair", .errmsg = true,
1122 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1123 [1] = SCA_SK_TYPE, /* type */ },
1124 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001125 { .name = "stat", .errmsg = true, .alias = "newstat",
1126 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001127 { .name = "statfs", .errmsg = true,
1128 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1129 { .name = "swapoff", .errmsg = true,
1130 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1131 { .name = "swapon", .errmsg = true,
1132 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001133 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001134 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001135 { .name = "tgkill", .errmsg = true,
1136 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1137 { .name = "tkill", .errmsg = true,
1138 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001139 { .name = "truncate", .errmsg = true,
1140 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001141 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001142 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001143 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1144 [1] = SCA_FILENAME, /* pathname */ }, },
1145 { .name = "utime", .errmsg = true,
1146 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001147 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001148 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1149 [1] = SCA_FILENAME, /* filename */ }, },
1150 { .name = "utimes", .errmsg = true,
1151 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001152 { .name = "vmsplice", .errmsg = true,
1153 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001154 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001155 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001156 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001157 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001158 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001159 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001160 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001161 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001162};
1163
1164static int syscall_fmt__cmp(const void *name, const void *fmtp)
1165{
1166 const struct syscall_fmt *fmt = fmtp;
1167 return strcmp(name, fmt->name);
1168}
1169
1170static struct syscall_fmt *syscall_fmt__find(const char *name)
1171{
1172 const int nmemb = ARRAY_SIZE(syscall_fmts);
1173 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1174}
1175
1176struct syscall {
1177 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001178 int nr_args;
1179 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001180 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001181 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001182 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001183 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001184 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001185};
1186
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001187static size_t fprintf_duration(unsigned long t, FILE *fp)
1188{
1189 double duration = (double)t / NSEC_PER_MSEC;
1190 size_t printed = fprintf(fp, "(");
1191
1192 if (duration >= 1.0)
1193 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1194 else if (duration >= 0.01)
1195 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1196 else
1197 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001198 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001199}
1200
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001201/**
1202 * filename.ptr: The filename char pointer that will be vfs_getname'd
1203 * filename.entry_str_pos: Where to insert the string translated from
1204 * filename.ptr by the vfs_getname tracepoint/kprobe.
1205 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001206struct thread_trace {
1207 u64 entry_time;
1208 u64 exit_time;
1209 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001210 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001211 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001212 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001213 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001214 struct {
1215 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001216 short int entry_str_pos;
1217 bool pending_open;
1218 unsigned int namelen;
1219 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001220 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001221 struct {
1222 int max;
1223 char **table;
1224 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001225
1226 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001227};
1228
1229static struct thread_trace *thread_trace__new(void)
1230{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001231 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1232
1233 if (ttrace)
1234 ttrace->paths.max = -1;
1235
David Ahernbf2575c2013-10-08 21:26:53 -06001236 ttrace->syscall_stats = intlist__new(NULL);
1237
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001238 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001239}
1240
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001241static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001242{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001243 struct thread_trace *ttrace;
1244
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001245 if (thread == NULL)
1246 goto fail;
1247
Namhyung Kim89dceb22014-10-06 09:46:03 +09001248 if (thread__priv(thread) == NULL)
1249 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001250
Namhyung Kim89dceb22014-10-06 09:46:03 +09001251 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001252 goto fail;
1253
Namhyung Kim89dceb22014-10-06 09:46:03 +09001254 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001255 ++ttrace->nr_events;
1256
1257 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001258fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001259 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001260 "WARNING: not enough memory, dropping samples!\n");
1261 return NULL;
1262}
1263
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001264#define TRACE_PFMAJ (1 << 0)
1265#define TRACE_PFMIN (1 << 1)
1266
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001267static const size_t trace__entry_str_size = 2048;
1268
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001269static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001270{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001271 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001272
1273 if (fd > ttrace->paths.max) {
1274 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1275
1276 if (npath == NULL)
1277 return -1;
1278
1279 if (ttrace->paths.max != -1) {
1280 memset(npath + ttrace->paths.max + 1, 0,
1281 (fd - ttrace->paths.max) * sizeof(char *));
1282 } else {
1283 memset(npath, 0, (fd + 1) * sizeof(char *));
1284 }
1285
1286 ttrace->paths.table = npath;
1287 ttrace->paths.max = fd;
1288 }
1289
1290 ttrace->paths.table[fd] = strdup(pathname);
1291
1292 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1293}
1294
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001295static int thread__read_fd_path(struct thread *thread, int fd)
1296{
1297 char linkname[PATH_MAX], pathname[PATH_MAX];
1298 struct stat st;
1299 int ret;
1300
1301 if (thread->pid_ == thread->tid) {
1302 scnprintf(linkname, sizeof(linkname),
1303 "/proc/%d/fd/%d", thread->pid_, fd);
1304 } else {
1305 scnprintf(linkname, sizeof(linkname),
1306 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1307 }
1308
1309 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1310 return -1;
1311
1312 ret = readlink(linkname, pathname, sizeof(pathname));
1313
1314 if (ret < 0 || ret > st.st_size)
1315 return -1;
1316
1317 pathname[ret] = '\0';
1318 return trace__set_fd_pathname(thread, fd, pathname);
1319}
1320
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001321static const char *thread__fd_path(struct thread *thread, int fd,
1322 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001323{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001324 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001325
1326 if (ttrace == NULL)
1327 return NULL;
1328
1329 if (fd < 0)
1330 return NULL;
1331
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001332 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001333 if (!trace->live)
1334 return NULL;
1335 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001336 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001337 return NULL;
1338 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001339
1340 return ttrace->paths.table[fd];
1341}
1342
1343static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1344 struct syscall_arg *arg)
1345{
1346 int fd = arg->val;
1347 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001348 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001349
1350 if (path)
1351 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1352
1353 return printed;
1354}
1355
1356static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1357 struct syscall_arg *arg)
1358{
1359 int fd = arg->val;
1360 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001361 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001362
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001363 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1364 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001365
1366 return printed;
1367}
1368
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001369static void thread__set_filename_pos(struct thread *thread, const char *bf,
1370 unsigned long ptr)
1371{
1372 struct thread_trace *ttrace = thread__priv(thread);
1373
1374 ttrace->filename.ptr = ptr;
1375 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1376}
1377
1378static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1379 struct syscall_arg *arg)
1380{
1381 unsigned long ptr = arg->val;
1382
1383 if (!arg->trace->vfs_getname)
1384 return scnprintf(bf, size, "%#x", ptr);
1385
1386 thread__set_filename_pos(arg->thread, bf, ptr);
1387 return 0;
1388}
1389
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001390static bool trace__filter_duration(struct trace *trace, double t)
1391{
1392 return t < (trace->duration_filter * NSEC_PER_MSEC);
1393}
1394
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001395static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1396{
1397 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1398
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001399 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001400}
1401
Namhyung Kimf15eb532012-10-05 14:02:16 +09001402static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001403static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001404
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001405static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001406{
1407 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001408 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001409}
1410
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001411static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001412 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001413{
1414 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001415 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001416
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001417 if (trace->multiple_threads) {
1418 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001419 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001420 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001421 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001422
1423 return printed;
1424}
1425
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001426static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001427 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001428{
1429 int ret = 0;
1430
1431 switch (event->header.type) {
1432 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001433 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001434 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001435 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001436 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001437 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001438 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001439 break;
1440 }
1441
1442 return ret;
1443}
1444
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001445static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001446 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001447 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001448 struct machine *machine)
1449{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001450 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001451 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001452}
1453
1454static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1455{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001456 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001457
1458 if (err)
1459 return err;
1460
David Ahern8fb598e2013-09-28 13:13:00 -06001461 trace->host = machine__new_host();
1462 if (trace->host == NULL)
1463 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001464
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001465 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001466 return -errno;
1467
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001468 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001469 evlist->threads, trace__tool_process, false,
1470 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001471 if (err)
1472 symbol__exit();
1473
1474 return err;
1475}
1476
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001477static int syscall__set_arg_fmts(struct syscall *sc)
1478{
1479 struct format_field *field;
1480 int idx = 0;
1481
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001482 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001483 if (sc->arg_scnprintf == NULL)
1484 return -1;
1485
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001486 if (sc->fmt)
1487 sc->arg_parm = sc->fmt->arg_parm;
1488
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001489 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001490 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1491 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1492 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001493 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001494 else if (strcmp(field->type, "pid_t") == 0)
1495 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001496 else if (strcmp(field->type, "umode_t") == 0)
1497 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001498 ++idx;
1499 }
1500
1501 return 0;
1502}
1503
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001504static int trace__read_syscall_info(struct trace *trace, int id)
1505{
1506 char tp_name[128];
1507 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001508 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001509
1510 if (name == NULL)
1511 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001512
1513 if (id > trace->syscalls.max) {
1514 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1515
1516 if (nsyscalls == NULL)
1517 return -1;
1518
1519 if (trace->syscalls.max != -1) {
1520 memset(nsyscalls + trace->syscalls.max + 1, 0,
1521 (id - trace->syscalls.max) * sizeof(*sc));
1522 } else {
1523 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1524 }
1525
1526 trace->syscalls.table = nsyscalls;
1527 trace->syscalls.max = id;
1528 }
1529
1530 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001531 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001532
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001533 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001534
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001535 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001536 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001537
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001538 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001539 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001540 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001541 }
1542
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001543 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001544 return -1;
1545
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001546 sc->args = sc->tp_format->format.fields;
1547 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001548 /*
1549 * We need to check and discard the first variable '__syscall_nr'
1550 * or 'nr' that mean the syscall number. It is needless here.
1551 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1552 */
1553 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001554 sc->args = sc->args->next;
1555 --sc->nr_args;
1556 }
1557
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001558 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1559
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001560 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001561}
1562
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001563static int trace__validate_ev_qualifier(struct trace *trace)
1564{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001565 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001566 struct str_node *pos;
1567
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001568 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1569 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1570 sizeof(trace->ev_qualifier_ids.entries[0]));
1571
1572 if (trace->ev_qualifier_ids.entries == NULL) {
1573 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1574 trace->output);
1575 err = -EINVAL;
1576 goto out;
1577 }
1578
1579 i = 0;
1580
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001581 strlist__for_each(pos, trace->ev_qualifier) {
1582 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001583 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001584
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001585 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001586 if (err == 0) {
1587 fputs("Error:\tInvalid syscall ", trace->output);
1588 err = -EINVAL;
1589 } else {
1590 fputs(", ", trace->output);
1591 }
1592
1593 fputs(sc, trace->output);
1594 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001595
1596 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001597 }
1598
1599 if (err < 0) {
1600 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1601 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001602 zfree(&trace->ev_qualifier_ids.entries);
1603 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001604 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001605out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001606 return err;
1607}
1608
David Ahern55d43bca2015-02-19 15:00:22 -05001609/*
1610 * args is to be interpreted as a series of longs but we need to handle
1611 * 8-byte unaligned accesses. args points to raw_data within the event
1612 * and raw_data is guaranteed to be 8-byte unaligned because it is
1613 * preceded by raw_size which is a u32. So we need to copy args to a temp
1614 * variable to read it. Most notably this avoids extended load instructions
1615 * on unaligned addresses
1616 */
1617
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001618static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001619 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001620 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001621{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001622 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001623 unsigned char *p;
1624 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001625
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001626 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001627 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001628 u8 bit = 1;
1629 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001630 .idx = 0,
1631 .mask = 0,
1632 .trace = trace,
1633 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001634 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001635
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001636 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001637 field = field->next, ++arg.idx, bit <<= 1) {
1638 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001639 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001640
1641 /* special care for unaligned accesses */
1642 p = args + sizeof(unsigned long) * arg.idx;
1643 memcpy(&val, p, sizeof(val));
1644
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001645 /*
1646 * Suppress this argument if its value is zero and
1647 * and we don't have a string associated in an
1648 * strarray for it.
1649 */
David Ahern55d43bca2015-02-19 15:00:22 -05001650 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001651 !(sc->arg_scnprintf &&
1652 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1653 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001654 continue;
1655
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001656 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001657 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001658 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bca2015-02-19 15:00:22 -05001659 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001660 if (sc->arg_parm)
1661 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001662 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1663 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001664 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001665 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bca2015-02-19 15:00:22 -05001666 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001667 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001668 }
1669 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001670 int i = 0;
1671
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001672 while (i < 6) {
David Ahern55d43bca2015-02-19 15:00:22 -05001673 /* special care for unaligned accesses */
1674 p = args + sizeof(unsigned long) * i;
1675 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001676 printed += scnprintf(bf + printed, size - printed,
1677 "%sarg%d: %ld",
David Ahern55d43bca2015-02-19 15:00:22 -05001678 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001679 ++i;
1680 }
1681 }
1682
1683 return printed;
1684}
1685
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001686typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001687 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001688 struct perf_sample *sample);
1689
1690static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001691 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001692{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001693
1694 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001695
1696 /*
1697 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1698 * before that, leaving at a higher verbosity level till that is
1699 * explained. Reproduced with plain ftrace with:
1700 *
1701 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1702 * grep "NR -1 " /t/trace_pipe
1703 *
1704 * After generating some load on the machine.
1705 */
1706 if (verbose > 1) {
1707 static u64 n;
1708 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1709 id, perf_evsel__name(evsel), ++n);
1710 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001711 return NULL;
1712 }
1713
1714 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1715 trace__read_syscall_info(trace, id))
1716 goto out_cant_read;
1717
1718 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1719 goto out_cant_read;
1720
1721 return &trace->syscalls.table[id];
1722
1723out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001724 if (verbose) {
1725 fprintf(trace->output, "Problems reading syscall %d", id);
1726 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1727 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1728 fputs(" information\n", trace->output);
1729 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001730 return NULL;
1731}
1732
David Ahernbf2575c2013-10-08 21:26:53 -06001733static void thread__update_stats(struct thread_trace *ttrace,
1734 int id, struct perf_sample *sample)
1735{
1736 struct int_node *inode;
1737 struct stats *stats;
1738 u64 duration = 0;
1739
1740 inode = intlist__findnew(ttrace->syscall_stats, id);
1741 if (inode == NULL)
1742 return;
1743
1744 stats = inode->priv;
1745 if (stats == NULL) {
1746 stats = malloc(sizeof(struct stats));
1747 if (stats == NULL)
1748 return;
1749 init_stats(stats);
1750 inode->priv = stats;
1751 }
1752
1753 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1754 duration = sample->time - ttrace->entry_time;
1755
1756 update_stats(stats, duration);
1757}
1758
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001759static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1760{
1761 struct thread_trace *ttrace;
1762 u64 duration;
1763 size_t printed;
1764
1765 if (trace->current == NULL)
1766 return 0;
1767
1768 ttrace = thread__priv(trace->current);
1769
1770 if (!ttrace->entry_pending)
1771 return 0;
1772
1773 duration = sample->time - ttrace->entry_time;
1774
1775 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1776 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1777 ttrace->entry_pending = false;
1778
1779 return printed;
1780}
1781
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001782static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001783 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001784 struct perf_sample *sample)
1785{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001786 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001787 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001788 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001789 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001790 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001791 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001792 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001793
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001794 if (sc == NULL)
1795 return -1;
1796
David Ahern8fb598e2013-09-28 13:13:00 -06001797 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001798 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001799 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001800 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001801
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001802 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001803
1804 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001805 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001806 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001807 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001808 }
1809
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001810 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001811 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001812
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001813 ttrace->entry_time = sample->time;
1814 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001815 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001816
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001817 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001818 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001819
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001820 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001821 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001822 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1823 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001824 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001825 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001826 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001827 /* See trace__vfs_getname & trace__sys_exit */
1828 ttrace->filename.pending_open = false;
1829 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001830
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001831 if (trace->current != thread) {
1832 thread__put(trace->current);
1833 trace->current = thread__get(thread);
1834 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001835 err = 0;
1836out_put:
1837 thread__put(thread);
1838 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001839}
1840
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001841static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1842 struct perf_sample *sample,
1843 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001844{
1845 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001846
1847 if (machine__resolve(trace->host, &al, sample) < 0 ||
1848 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1849 return -1;
1850
1851 return 0;
1852}
1853
1854static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1855{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001856 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001857 const unsigned int print_opts = EVSEL__PRINT_SYM |
1858 EVSEL__PRINT_DSO |
1859 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001860
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001861 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001862}
1863
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001864static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001865 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001866 struct perf_sample *sample)
1867{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001868 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001869 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001870 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001871 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001872 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001873 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001874
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001875 if (sc == NULL)
1876 return -1;
1877
David Ahern8fb598e2013-09-28 13:13:00 -06001878 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001879 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001880 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001881 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001882
David Ahernbf2575c2013-10-08 21:26:53 -06001883 if (trace->summary)
1884 thread__update_stats(ttrace, id, sample);
1885
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001886 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001887
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001888 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001889 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1890 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001891 ++trace->stats.vfs_getname;
1892 }
1893
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001894 ttrace->exit_time = sample->time;
1895
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001896 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001897 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001898 if (trace__filter_duration(trace, duration))
1899 goto out;
1900 } else if (trace->duration_filter)
1901 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001902
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001903 if (sample->callchain) {
1904 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1905 if (callchain_ret == 0) {
1906 if (callchain_cursor.nr < trace->min_stack)
1907 goto out;
1908 callchain_ret = 1;
1909 }
1910 }
1911
David Ahernfd2eaba2013-11-12 09:31:15 -07001912 if (trace->summary_only)
1913 goto out;
1914
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001915 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001916
1917 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001918 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001919 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001920 fprintf(trace->output, " ... [");
1921 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1922 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001923 }
1924
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001925 if (sc->fmt == NULL) {
1926signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001927 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001928 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001929 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001930 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1931 *e = audit_errno_to_name(-ret);
1932
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001933 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001934 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001935 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001936 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001937 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001938 else if (sc->fmt->errpid) {
1939 struct thread *child = machine__find_thread(trace->host, ret, ret);
1940
1941 if (child != NULL) {
1942 fprintf(trace->output, ") = %ld", ret);
1943 if (child->comm_set)
1944 fprintf(trace->output, " (%s)", thread__comm_str(child));
1945 thread__put(child);
1946 }
1947 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001948 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001949
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001950 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001951
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001952 if (callchain_ret > 0)
1953 trace__fprintf_callchain(trace, sample);
1954 else if (callchain_ret < 0)
1955 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001956out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001957 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001958 err = 0;
1959out_put:
1960 thread__put(thread);
1961 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001962}
1963
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001964static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001965 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001966 struct perf_sample *sample)
1967{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001968 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1969 struct thread_trace *ttrace;
1970 size_t filename_len, entry_str_len, to_move;
1971 ssize_t remaining_space;
1972 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001973 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001974
1975 if (!thread)
1976 goto out;
1977
1978 ttrace = thread__priv(thread);
1979 if (!ttrace)
1980 goto out;
1981
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001982 filename_len = strlen(filename);
1983
1984 if (ttrace->filename.namelen < filename_len) {
1985 char *f = realloc(ttrace->filename.name, filename_len + 1);
1986
1987 if (f == NULL)
1988 goto out;
1989
1990 ttrace->filename.namelen = filename_len;
1991 ttrace->filename.name = f;
1992 }
1993
1994 strcpy(ttrace->filename.name, filename);
1995 ttrace->filename.pending_open = true;
1996
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001997 if (!ttrace->filename.ptr)
1998 goto out;
1999
2000 entry_str_len = strlen(ttrace->entry_str);
2001 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2002 if (remaining_space <= 0)
2003 goto out;
2004
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002005 if (filename_len > (size_t)remaining_space) {
2006 filename += filename_len - remaining_space;
2007 filename_len = remaining_space;
2008 }
2009
2010 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2011 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2012 memmove(pos + filename_len, pos, to_move);
2013 memcpy(pos, filename, filename_len);
2014
2015 ttrace->filename.ptr = 0;
2016 ttrace->filename.entry_str_pos = 0;
2017out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002018 return 0;
2019}
2020
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002021static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002022 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002023 struct perf_sample *sample)
2024{
2025 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2026 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06002027 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03002028 sample->pid,
2029 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002030 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002031
2032 if (ttrace == NULL)
2033 goto out_dump;
2034
2035 ttrace->runtime_ms += runtime_ms;
2036 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002037 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002038 return 0;
2039
2040out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002041 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002042 evsel->name,
2043 perf_evsel__strval(evsel, sample, "comm"),
2044 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2045 runtime,
2046 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002047 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002048 return 0;
2049}
2050
Wang Nan1d6c9402016-02-26 09:31:55 +00002051static void bpf_output__printer(enum binary_printer_ops op,
2052 unsigned int val, void *extra)
2053{
2054 FILE *output = extra;
2055 unsigned char ch = (unsigned char)val;
2056
2057 switch (op) {
2058 case BINARY_PRINT_CHAR_DATA:
2059 fprintf(output, "%c", isprint(ch) ? ch : '.');
2060 break;
2061 case BINARY_PRINT_DATA_BEGIN:
2062 case BINARY_PRINT_LINE_BEGIN:
2063 case BINARY_PRINT_ADDR:
2064 case BINARY_PRINT_NUM_DATA:
2065 case BINARY_PRINT_NUM_PAD:
2066 case BINARY_PRINT_SEP:
2067 case BINARY_PRINT_CHAR_PAD:
2068 case BINARY_PRINT_LINE_END:
2069 case BINARY_PRINT_DATA_END:
2070 default:
2071 break;
2072 }
2073}
2074
2075static void bpf_output__fprintf(struct trace *trace,
2076 struct perf_sample *sample)
2077{
2078 print_binary(sample->raw_data, sample->raw_size, 8,
2079 bpf_output__printer, trace->output);
2080}
2081
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002082static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2083 union perf_event *event __maybe_unused,
2084 struct perf_sample *sample)
2085{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002086 int callchain_ret = 0;
2087
2088 if (sample->callchain) {
2089 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2090 if (callchain_ret == 0) {
2091 if (callchain_cursor.nr < trace->min_stack)
2092 goto out;
2093 callchain_ret = 1;
2094 }
2095 }
2096
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002097 trace__printf_interrupted_entry(trace, sample);
2098 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002099
2100 if (trace->trace_syscalls)
2101 fprintf(trace->output, "( ): ");
2102
2103 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002104
Wang Nan1d6c9402016-02-26 09:31:55 +00002105 if (perf_evsel__is_bpf_output(evsel)) {
2106 bpf_output__fprintf(trace, sample);
2107 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002108 event_format__fprintf(evsel->tp_format, sample->cpu,
2109 sample->raw_data, sample->raw_size,
2110 trace->output);
2111 }
2112
2113 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03002114
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002115 if (callchain_ret > 0)
2116 trace__fprintf_callchain(trace, sample);
2117 else if (callchain_ret < 0)
2118 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
2119out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002120 return 0;
2121}
2122
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002123static void print_location(FILE *f, struct perf_sample *sample,
2124 struct addr_location *al,
2125 bool print_dso, bool print_sym)
2126{
2127
2128 if ((verbose || print_dso) && al->map)
2129 fprintf(f, "%s@", al->map->dso->long_name);
2130
2131 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002132 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002133 al->addr - al->sym->start);
2134 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002135 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002136 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002137 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002138}
2139
2140static int trace__pgfault(struct trace *trace,
2141 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002142 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002143 struct perf_sample *sample)
2144{
2145 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002146 struct addr_location al;
2147 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002148 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002149 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002150 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002151
2152 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002153
2154 if (sample->callchain) {
2155 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2156 if (callchain_ret == 0) {
2157 if (callchain_cursor.nr < trace->min_stack)
2158 goto out_put;
2159 callchain_ret = 1;
2160 }
2161 }
2162
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002163 ttrace = thread__trace(thread, trace->output);
2164 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002165 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002166
2167 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2168 ttrace->pfmaj++;
2169 else
2170 ttrace->pfmin++;
2171
2172 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002173 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002174
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002175 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002176 sample->ip, &al);
2177
2178 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2179
2180 fprintf(trace->output, "%sfault [",
2181 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2182 "maj" : "min");
2183
2184 print_location(trace->output, sample, &al, false, true);
2185
2186 fprintf(trace->output, "] => ");
2187
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002188 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002189 sample->addr, &al);
2190
2191 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002192 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002193 MAP__FUNCTION, sample->addr, &al);
2194
2195 if (al.map)
2196 map_type = 'x';
2197 else
2198 map_type = '?';
2199 }
2200
2201 print_location(trace->output, sample, &al, true, false);
2202
2203 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002204
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002205 if (callchain_ret > 0)
2206 trace__fprintf_callchain(trace, sample);
2207 else if (callchain_ret < 0)
2208 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002209out:
2210 err = 0;
2211out_put:
2212 thread__put(thread);
2213 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002214}
2215
David Ahernbdc89662013-08-28 22:29:53 -06002216static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2217{
2218 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2219 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2220 return false;
2221
2222 if (trace->pid_list || trace->tid_list)
2223 return true;
2224
2225 return false;
2226}
2227
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002228static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002229 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002230 struct perf_sample *sample)
2231{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002232 /*
2233 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2234 * and don't use sample->time unconditionally, we may end up having
2235 * some other event in the future without PERF_SAMPLE_TIME for good
2236 * reason, i.e. we may not be interested in its timestamps, just in
2237 * it taking place, picking some piece of information when it
2238 * appears in our event stream (vfs_getname comes to mind).
2239 */
2240 if (trace->base_time == 0 && !trace->full_time &&
2241 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002242 trace->base_time = sample->time;
2243}
2244
David Ahern6810fc92013-08-28 22:29:52 -06002245static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002246 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002247 struct perf_sample *sample,
2248 struct perf_evsel *evsel,
2249 struct machine *machine __maybe_unused)
2250{
2251 struct trace *trace = container_of(tool, struct trace, tool);
2252 int err = 0;
2253
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002254 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002255
David Ahernbdc89662013-08-28 22:29:53 -06002256 if (skip_sample(trace, sample))
2257 return 0;
2258
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002259 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002260
David Ahern31605652013-12-04 19:41:41 -07002261 if (handler) {
2262 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002263 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002264 }
David Ahern6810fc92013-08-28 22:29:52 -06002265
2266 return err;
2267}
2268
David Ahernbdc89662013-08-28 22:29:53 -06002269static int parse_target_str(struct trace *trace)
2270{
2271 if (trace->opts.target.pid) {
2272 trace->pid_list = intlist__new(trace->opts.target.pid);
2273 if (trace->pid_list == NULL) {
2274 pr_err("Error parsing process id string\n");
2275 return -EINVAL;
2276 }
2277 }
2278
2279 if (trace->opts.target.tid) {
2280 trace->tid_list = intlist__new(trace->opts.target.tid);
2281 if (trace->tid_list == NULL) {
2282 pr_err("Error parsing thread id string\n");
2283 return -EINVAL;
2284 }
2285 }
2286
2287 return 0;
2288}
2289
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002290static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002291{
2292 unsigned int rec_argc, i, j;
2293 const char **rec_argv;
2294 const char * const record_args[] = {
2295 "record",
2296 "-R",
2297 "-m", "1024",
2298 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002299 };
2300
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002301 const char * const sc_args[] = { "-e", };
2302 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2303 const char * const majpf_args[] = { "-e", "major-faults" };
2304 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2305 const char * const minpf_args[] = { "-e", "minor-faults" };
2306 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2307
David Ahern9aca7f12013-12-04 19:41:39 -07002308 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002309 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2310 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002311 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2312
2313 if (rec_argv == NULL)
2314 return -ENOMEM;
2315
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002316 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002317 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002318 rec_argv[j++] = record_args[i];
2319
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002320 if (trace->trace_syscalls) {
2321 for (i = 0; i < sc_args_nr; i++)
2322 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002323
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002324 /* event string may be different for older kernels - e.g., RHEL6 */
2325 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2326 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2327 else if (is_valid_tracepoint("syscalls:sys_enter"))
2328 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2329 else {
2330 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2331 return -1;
2332 }
David Ahern9aca7f12013-12-04 19:41:39 -07002333 }
David Ahern9aca7f12013-12-04 19:41:39 -07002334
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002335 if (trace->trace_pgfaults & TRACE_PFMAJ)
2336 for (i = 0; i < majpf_args_nr; i++)
2337 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002338
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002339 if (trace->trace_pgfaults & TRACE_PFMIN)
2340 for (i = 0; i < minpf_args_nr; i++)
2341 rec_argv[j++] = minpf_args[i];
2342
2343 for (i = 0; i < (unsigned int)argc; i++)
2344 rec_argv[j++] = argv[i];
2345
2346 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002347}
2348
David Ahernbf2575c2013-10-08 21:26:53 -06002349static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2350
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002351static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002352{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002353 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002354
2355 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002356 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002357
2358 if (perf_evsel__field(evsel, "pathname") == NULL) {
2359 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002360 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002361 }
2362
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002363 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002364 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002365 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002366}
2367
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002368static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002369{
2370 struct perf_evsel *evsel;
2371 struct perf_event_attr attr = {
2372 .type = PERF_TYPE_SOFTWARE,
2373 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002374 };
2375
2376 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002377 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002378
2379 event_attr_init(&attr);
2380
2381 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002382 if (evsel)
2383 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002384
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002385 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002386}
2387
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002388static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2389{
2390 const u32 type = event->header.type;
2391 struct perf_evsel *evsel;
2392
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002393 if (type != PERF_RECORD_SAMPLE) {
2394 trace__process_event(trace, trace->host, event, sample);
2395 return;
2396 }
2397
2398 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2399 if (evsel == NULL) {
2400 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2401 return;
2402 }
2403
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002404 trace__set_base_time(trace, evsel, sample);
2405
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002406 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2407 sample->raw_data == NULL) {
2408 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2409 perf_evsel__name(evsel), sample->tid,
2410 sample->cpu, sample->raw_size);
2411 } else {
2412 tracepoint_handler handler = evsel->handler;
2413 handler(trace, evsel, event, sample);
2414 }
2415}
2416
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002417static int trace__add_syscall_newtp(struct trace *trace)
2418{
2419 int ret = -1;
2420 struct perf_evlist *evlist = trace->evlist;
2421 struct perf_evsel *sys_enter, *sys_exit;
2422
2423 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2424 if (sys_enter == NULL)
2425 goto out;
2426
2427 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2428 goto out_delete_sys_enter;
2429
2430 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2431 if (sys_exit == NULL)
2432 goto out_delete_sys_enter;
2433
2434 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2435 goto out_delete_sys_exit;
2436
2437 perf_evlist__add(evlist, sys_enter);
2438 perf_evlist__add(evlist, sys_exit);
2439
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002440 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002441 /*
2442 * We're interested only in the user space callchain
2443 * leading to the syscall, allow overriding that for
2444 * debugging reasons using --kernel_syscall_callchains
2445 */
2446 sys_exit->attr.exclude_callchain_kernel = 1;
2447 }
2448
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002449 trace->syscalls.events.sys_enter = sys_enter;
2450 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002451
2452 ret = 0;
2453out:
2454 return ret;
2455
2456out_delete_sys_exit:
2457 perf_evsel__delete_priv(sys_exit);
2458out_delete_sys_enter:
2459 perf_evsel__delete_priv(sys_enter);
2460 goto out;
2461}
2462
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002463static int trace__set_ev_qualifier_filter(struct trace *trace)
2464{
2465 int err = -1;
2466 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2467 trace->ev_qualifier_ids.nr,
2468 trace->ev_qualifier_ids.entries);
2469
2470 if (filter == NULL)
2471 goto out_enomem;
2472
2473 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2474 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2475
2476 free(filter);
2477out:
2478 return err;
2479out_enomem:
2480 errno = ENOMEM;
2481 goto out;
2482}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002483
Namhyung Kimf15eb532012-10-05 14:02:16 +09002484static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002485{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002486 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002487 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002488 int err = -1, i;
2489 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002490 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002491 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002492
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002493 trace->live = true;
2494
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002495 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002496 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002497
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002498 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002499 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002500
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002501 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2502 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2503 if (pgfault_maj == NULL)
2504 goto out_error_mem;
2505 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002506 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002507
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002508 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2509 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2510 if (pgfault_min == NULL)
2511 goto out_error_mem;
2512 perf_evlist__add(evlist, pgfault_min);
2513 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002514
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002515 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002516 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2517 trace__sched_stat_runtime))
2518 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002519
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002520 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2521 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002522 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002523 goto out_delete_evlist;
2524 }
2525
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002526 err = trace__symbols_init(trace, evlist);
2527 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002528 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002529 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002530 }
2531
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002532 perf_evlist__config(evlist, &trace->opts, NULL);
2533
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002534 if (callchain_param.enabled) {
2535 bool use_identifier = false;
2536
2537 if (trace->syscalls.events.sys_exit) {
2538 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2539 &trace->opts, &callchain_param);
2540 use_identifier = true;
2541 }
2542
2543 if (pgfault_maj) {
2544 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2545 use_identifier = true;
2546 }
2547
2548 if (pgfault_min) {
2549 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2550 use_identifier = true;
2551 }
2552
2553 if (use_identifier) {
2554 /*
2555 * Now we have evsels with different sample_ids, use
2556 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2557 * from a fixed position in each ring buffer record.
2558 *
2559 * As of this the changeset introducing this comment, this
2560 * isn't strictly needed, as the fields that can come before
2561 * PERF_SAMPLE_ID are all used, but we'll probably disable
2562 * some of those for things like copying the payload of
2563 * pointer syscall arguments, and for vfs_getname we don't
2564 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2565 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2566 */
2567 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2568 perf_evlist__reset_sample_bit(evlist, ID);
2569 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002570 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002571
Namhyung Kimf15eb532012-10-05 14:02:16 +09002572 signal(SIGCHLD, sig_handler);
2573 signal(SIGINT, sig_handler);
2574
2575 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002576 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002577 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002578 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002579 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002580 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002581 }
2582 }
2583
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002584 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002585 if (err < 0)
2586 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002587
Wang Nanba504232016-02-26 09:31:54 +00002588 err = bpf__apply_obj_config();
2589 if (err) {
2590 char errbuf[BUFSIZ];
2591
2592 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2593 pr_err("ERROR: Apply config to BPF failed: %s\n",
2594 errbuf);
2595 goto out_error_open;
2596 }
2597
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002598 /*
2599 * Better not use !target__has_task() here because we need to cover the
2600 * case where no threads were specified in the command line, but a
2601 * workload was, and in that case we will fill in the thread_map when
2602 * we fork the workload in perf_evlist__prepare_workload.
2603 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002604 if (trace->filter_pids.nr > 0)
2605 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002606 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002607 err = perf_evlist__set_filter_pid(evlist, getpid());
2608
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002609 if (err < 0)
2610 goto out_error_mem;
2611
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002612 if (trace->ev_qualifier_ids.nr > 0) {
2613 err = trace__set_ev_qualifier_filter(trace);
2614 if (err < 0)
2615 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002616
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002617 pr_debug("event qualifier tracepoint filter: %s\n",
2618 trace->syscalls.events.sys_exit->filter);
2619 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002620
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002621 err = perf_evlist__apply_filters(evlist, &evsel);
2622 if (err < 0)
2623 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002624
Jiri Olsaf8850372013-11-28 17:57:22 +01002625 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002626 if (err < 0)
2627 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002628
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002629 if (!target__none(&trace->opts.target))
2630 perf_evlist__enable(evlist);
2631
Namhyung Kimf15eb532012-10-05 14:02:16 +09002632 if (forks)
2633 perf_evlist__start_workload(evlist);
2634
Jiri Olsae13798c2015-06-23 00:36:02 +02002635 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002636 evlist->threads->nr > 1 ||
2637 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002638again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002639 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002640
2641 for (i = 0; i < evlist->nr_mmaps; i++) {
2642 union perf_event *event;
2643
2644 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002645 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002646
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002647 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002648
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002649 err = perf_evlist__parse_sample(evlist, event, &sample);
2650 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002651 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002652 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002653 }
2654
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002655 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002656next_event:
2657 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002658
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002659 if (interrupted)
2660 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002661
2662 if (done && !draining) {
2663 perf_evlist__disable(evlist);
2664 draining = true;
2665 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002666 }
2667 }
2668
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002669 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002670 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002671
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002672 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2673 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2674 draining = true;
2675
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002676 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002677 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002678 } else {
2679 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002680 }
2681
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002682out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002683 thread__zput(trace->current);
2684
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002685 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002686
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002687 if (!err) {
2688 if (trace->summary)
2689 trace__fprintf_thread_summary(trace, trace->output);
2690
2691 if (trace->show_tool_stats) {
2692 fprintf(trace->output, "Stats:\n "
2693 " vfs_getname : %" PRIu64 "\n"
2694 " proc_getname: %" PRIu64 "\n",
2695 trace->stats.vfs_getname,
2696 trace->stats.proc_getname);
2697 }
2698 }
David Ahernbf2575c2013-10-08 21:26:53 -06002699
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002700out_delete_evlist:
2701 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002702 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002703 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002704 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002705{
2706 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002707
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002708out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002709 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002710 goto out_error;
2711
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002712out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002713 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002714 goto out_error;
2715
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002716out_error_mmap:
2717 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2718 goto out_error;
2719
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002720out_error_open:
2721 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2722
2723out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002724 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302725 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002726
2727out_error_apply_filters:
2728 fprintf(trace->output,
2729 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2730 evsel->filter, perf_evsel__name(evsel), errno,
2731 strerror_r(errno, errbuf, sizeof(errbuf)));
2732 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002733}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002734out_error_mem:
2735 fprintf(trace->output, "Not enough memory to run!\n");
2736 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002737
2738out_errno:
2739 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2740 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002741}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002742
David Ahern6810fc92013-08-28 22:29:52 -06002743static int trace__replay(struct trace *trace)
2744{
2745 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002746 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002747 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002748 struct perf_data_file file = {
2749 .path = input_name,
2750 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002751 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002752 };
David Ahern6810fc92013-08-28 22:29:52 -06002753 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002754 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002755 int err = -1;
2756
2757 trace->tool.sample = trace__process_sample;
2758 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002759 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002760 trace->tool.comm = perf_event__process_comm;
2761 trace->tool.exit = perf_event__process_exit;
2762 trace->tool.fork = perf_event__process_fork;
2763 trace->tool.attr = perf_event__process_attr;
2764 trace->tool.tracing_data = perf_event__process_tracing_data;
2765 trace->tool.build_id = perf_event__process_build_id;
2766
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002767 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002768 trace->tool.ordering_requires_timestamps = true;
2769
2770 /* add tid to output */
2771 trace->multiple_threads = true;
2772
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002773 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002774 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002775 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002776
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002777 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002778 goto out;
2779
David Ahern8fb598e2013-09-28 13:13:00 -06002780 trace->host = &session->machines.host;
2781
David Ahern6810fc92013-08-28 22:29:52 -06002782 err = perf_session__set_tracepoints_handlers(session, handlers);
2783 if (err)
2784 goto out;
2785
Namhyung Kim003824e2013-11-12 15:25:00 +09002786 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2787 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002788 /* older kernels have syscalls tp versus raw_syscalls */
2789 if (evsel == NULL)
2790 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2791 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002792
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002793 if (evsel &&
2794 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2795 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002796 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2797 goto out;
2798 }
2799
2800 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2801 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002802 if (evsel == NULL)
2803 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2804 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002805 if (evsel &&
2806 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2807 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002808 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002809 goto out;
2810 }
2811
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002812 evlist__for_each(session->evlist, evsel) {
2813 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2814 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2815 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2816 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2817 evsel->handler = trace__pgfault;
2818 }
2819
David Ahernbdc89662013-08-28 22:29:53 -06002820 err = parse_target_str(trace);
2821 if (err != 0)
2822 goto out;
2823
David Ahern6810fc92013-08-28 22:29:52 -06002824 setup_pager();
2825
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002826 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002827 if (err)
2828 pr_err("Failed to process events, error %d", err);
2829
David Ahernbf2575c2013-10-08 21:26:53 -06002830 else if (trace->summary)
2831 trace__fprintf_thread_summary(trace, trace->output);
2832
David Ahern6810fc92013-08-28 22:29:52 -06002833out:
2834 perf_session__delete(session);
2835
2836 return err;
2837}
2838
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002839static size_t trace__fprintf_threads_header(FILE *fp)
2840{
2841 size_t printed;
2842
Pekka Enberg99ff7152013-11-12 16:42:14 +02002843 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002844
2845 return printed;
2846}
2847
2848static size_t thread__dump_stats(struct thread_trace *ttrace,
2849 struct trace *trace, FILE *fp)
2850{
2851 struct stats *stats;
2852 size_t printed = 0;
2853 struct syscall *sc;
2854 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2855
2856 if (inode == NULL)
2857 return 0;
2858
2859 printed += fprintf(fp, "\n");
2860
Milian Wolff834fd462015-08-06 11:24:29 +02002861 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2862 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2863 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002864
David Ahernbf2575c2013-10-08 21:26:53 -06002865 /* each int_node is a syscall */
2866 while (inode) {
2867 stats = inode->priv;
2868 if (stats) {
2869 double min = (double)(stats->min) / NSEC_PER_MSEC;
2870 double max = (double)(stats->max) / NSEC_PER_MSEC;
2871 double avg = avg_stats(stats);
2872 double pct;
2873 u64 n = (u64) stats->n;
2874
2875 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2876 avg /= NSEC_PER_MSEC;
2877
2878 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002879 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002880 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
2881 n, avg * n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002882 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002883 }
2884
2885 inode = intlist__next(inode);
2886 }
2887
2888 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002889
2890 return printed;
2891}
2892
David Ahern896cbb52013-09-28 13:12:59 -06002893/* struct used to pass data to per-thread function */
2894struct summary_data {
2895 FILE *fp;
2896 struct trace *trace;
2897 size_t printed;
2898};
2899
2900static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2901{
2902 struct summary_data *data = priv;
2903 FILE *fp = data->fp;
2904 size_t printed = data->printed;
2905 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002906 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002907 double ratio;
2908
2909 if (ttrace == NULL)
2910 return 0;
2911
2912 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2913
Pekka Enberg15e65c62013-11-14 18:43:30 +02002914 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002915 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002916 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002917 if (ttrace->pfmaj)
2918 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2919 if (ttrace->pfmin)
2920 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002921 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002922 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002923
2924 data->printed += printed;
2925
2926 return 0;
2927}
2928
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002929static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2930{
David Ahern896cbb52013-09-28 13:12:59 -06002931 struct summary_data data = {
2932 .fp = fp,
2933 .trace = trace
2934 };
2935 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002936
David Ahern896cbb52013-09-28 13:12:59 -06002937 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002938
David Ahern896cbb52013-09-28 13:12:59 -06002939 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002940}
2941
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002942static int trace__set_duration(const struct option *opt, const char *str,
2943 int unset __maybe_unused)
2944{
2945 struct trace *trace = opt->value;
2946
2947 trace->duration_filter = atof(str);
2948 return 0;
2949}
2950
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002951static int trace__set_filter_pids(const struct option *opt, const char *str,
2952 int unset __maybe_unused)
2953{
2954 int ret = -1;
2955 size_t i;
2956 struct trace *trace = opt->value;
2957 /*
2958 * FIXME: introduce a intarray class, plain parse csv and create a
2959 * { int nr, int entries[] } struct...
2960 */
2961 struct intlist *list = intlist__new(str);
2962
2963 if (list == NULL)
2964 return -1;
2965
2966 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2967 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2968
2969 if (trace->filter_pids.entries == NULL)
2970 goto out;
2971
2972 trace->filter_pids.entries[0] = getpid();
2973
2974 for (i = 1; i < trace->filter_pids.nr; ++i)
2975 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2976
2977 intlist__delete(list);
2978 ret = 0;
2979out:
2980 return ret;
2981}
2982
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002983static int trace__open_output(struct trace *trace, const char *filename)
2984{
2985 struct stat st;
2986
2987 if (!stat(filename, &st) && st.st_size) {
2988 char oldname[PATH_MAX];
2989
2990 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2991 unlink(oldname);
2992 rename(filename, oldname);
2993 }
2994
2995 trace->output = fopen(filename, "w");
2996
2997 return trace->output == NULL ? -errno : 0;
2998}
2999
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003000static int parse_pagefaults(const struct option *opt, const char *str,
3001 int unset __maybe_unused)
3002{
3003 int *trace_pgfaults = opt->value;
3004
3005 if (strcmp(str, "all") == 0)
3006 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
3007 else if (strcmp(str, "maj") == 0)
3008 *trace_pgfaults |= TRACE_PFMAJ;
3009 else if (strcmp(str, "min") == 0)
3010 *trace_pgfaults |= TRACE_PFMIN;
3011 else
3012 return -1;
3013
3014 return 0;
3015}
3016
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003017static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3018{
3019 struct perf_evsel *evsel;
3020
3021 evlist__for_each(evlist, evsel)
3022 evsel->handler = handler;
3023}
3024
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003025int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3026{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003027 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003028 "perf trace [<options>] [<command>]",
3029 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003030 "perf trace record [<options>] [<command>]",
3031 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003032 NULL
3033 };
3034 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003035 .syscalls = {
3036 . max = -1,
3037 },
3038 .opts = {
3039 .target = {
3040 .uid = UINT_MAX,
3041 .uses_mmap = true,
3042 },
3043 .user_freq = UINT_MAX,
3044 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003045 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003046 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003047 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003048 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003049 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003050 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003051 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003052 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003053 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003054 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003055 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003056 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003057 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003058 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3059 "event selector. use 'perf list' to list available events",
3060 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003061 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3062 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003063 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03003064 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003065 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003066 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003067 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3068 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003069 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003070 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003071 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3072 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003073 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003074 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003075 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003076 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003077 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003078 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003079 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3080 "number of mmap data pages",
3081 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003082 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003083 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003084 OPT_CALLBACK(0, "duration", &trace, "float",
3085 "show only events with duration > N.M ms",
3086 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003087 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003088 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003089 OPT_BOOLEAN('T', "time", &trace.full_time,
3090 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003091 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3092 "Show only syscall summary with statistics"),
3093 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3094 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003095 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3096 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003097 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003098 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003099 OPT_CALLBACK(0, "call-graph", &trace.opts,
3100 "record_mode[,record_size]", record_callchain_help,
3101 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003102 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3103 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03003104 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3105 "Set the minimum stack depth when parsing the callchain, "
3106 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03003107 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3108 "Set the maximum stack depth when parsing the callchain, "
3109 "anything beyond the specified depth will be ignored. "
3110 "Default: " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04003111 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3112 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003113 OPT_END()
3114 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003115 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003116 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003117 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003118 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003119 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003120
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003121 signal(SIGSEGV, sighandler_dump_stack);
3122 signal(SIGFPE, sighandler_dump_stack);
3123
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003124 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003125 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003126
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003127 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003128 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003129 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003130 goto out;
3131 }
3132
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003133 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3134 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003135
Wang Nand7888572016-04-08 15:07:24 +00003136 err = bpf__setup_stdout(trace.evlist);
3137 if (err) {
3138 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3139 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3140 goto out;
3141 }
3142
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003143 err = -1;
3144
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003145 if (trace.trace_pgfaults) {
3146 trace.opts.sample_address = true;
3147 trace.opts.sample_time = true;
3148 }
3149
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003150 if (trace.opts.mmap_pages == UINT_MAX)
3151 mmap_pages_user_set = false;
3152
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003153 if (trace.max_stack == UINT_MAX) {
3154 trace.max_stack = PERF_MAX_STACK_DEPTH;
3155 max_stack_user_set = false;
3156 }
3157
3158#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003159 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003160 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
3161#endif
3162
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003163 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003164 if (!mmap_pages_user_set && geteuid() == 0)
3165 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3166
Milian Wolff566a0882016-04-08 13:34:15 +02003167 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003168 }
Milian Wolff566a0882016-04-08 13:34:15 +02003169
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003170 if (trace.evlist->nr_entries > 0)
3171 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3172
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003173 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3174 return trace__record(&trace, argc-1, &argv[1]);
3175
3176 /* summary_only implies summary option, but don't overwrite summary if set */
3177 if (trace.summary_only)
3178 trace.summary = trace.summary_only;
3179
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003180 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3181 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003182 pr_err("Please specify something to trace.\n");
3183 return -1;
3184 }
3185
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003186 if (!trace.trace_syscalls && ev_qualifier_str) {
3187 pr_err("The -e option can't be used with --no-syscalls.\n");
3188 goto out;
3189 }
3190
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003191 if (output_name != NULL) {
3192 err = trace__open_output(&trace, output_name);
3193 if (err < 0) {
3194 perror("failed to create output file");
3195 goto out;
3196 }
3197 }
3198
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003199 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3200
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003201 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003202 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03003203 struct strlist_config slist_config = {
3204 .dirname = system_path(STRACE_GROUPS_DIR),
3205 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003206
3207 trace.not_ev_qualifier = *s == '!';
3208 if (trace.not_ev_qualifier)
3209 ++s;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03003210 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003211 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003212 fputs("Not enough memory to parse event qualifier",
3213 trace.output);
3214 err = -ENOMEM;
3215 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003216 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003217
3218 err = trace__validate_ev_qualifier(&trace);
3219 if (err)
3220 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003221 }
3222
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003223 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003224 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003225 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003226 fprintf(trace.output, "%s", bf);
3227 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003228 }
3229
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003230 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003231 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003232 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003233 fprintf(trace.output, "%s", bf);
3234 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003235 }
3236
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003237 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003238 trace.opts.target.system_wide = true;
3239
David Ahern6810fc92013-08-28 22:29:52 -06003240 if (input_name)
3241 err = trace__replay(&trace);
3242 else
3243 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003244
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003245out_close:
3246 if (output_name != NULL)
3247 fclose(trace.output);
3248out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003249 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003250}