blob: 48b00f0425991926b9f844678715b008f57714b2 [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 Ahern55d43bc2015-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 Ahern55d43bc2015-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,
Arnaldo Carvalho de Meloccd9b2a2016-04-26 11:40:17 -03001046 .arg_scnprintf = { [2] = SCA_INT, /* cpu */
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001047 [3] = SCA_FD, /* group_fd */
1048 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001049 { .name = "pipe2", .errmsg = true,
1050 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001051 { .name = "poll", .errmsg = true, .timeout = true, },
1052 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001053 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001054 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001055 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001056 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001057 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001058 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001059 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001060 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001061 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001062 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001063 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001064 { .name = "readlink", .errmsg = true,
1065 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001066 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001067 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1068 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001069 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001070 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001071 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001072 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1073 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001074 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001075 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1076 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001077 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001078 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1079 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001080 { .name = "removexattr", .errmsg = true,
1081 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001082 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001083 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001084 { .name = "rmdir", .errmsg = true,
1085 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001086 { .name = "rt_sigaction", .errmsg = true,
1087 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001088 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001089 { .name = "rt_sigqueueinfo", .errmsg = true,
1090 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1091 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1092 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001093 { .name = "sched_setscheduler", .errmsg = true,
1094 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001095 { .name = "seccomp", .errmsg = true,
1096 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
1097 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001098 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001099 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001100 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1101 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001102 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001103 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1104 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001105 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001106 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1107 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001108 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001109 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001110 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001111 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001112 { .name = "setxattr", .errmsg = true,
1113 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001114 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001115 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001116 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001117 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1118 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001119 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001120 { .name = "socketpair", .errmsg = true,
1121 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1122 [1] = SCA_SK_TYPE, /* type */ },
1123 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001124 { .name = "stat", .errmsg = true, .alias = "newstat",
1125 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001126 { .name = "statfs", .errmsg = true,
1127 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1128 { .name = "swapoff", .errmsg = true,
1129 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1130 { .name = "swapon", .errmsg = true,
1131 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001132 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001133 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001134 { .name = "tgkill", .errmsg = true,
1135 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1136 { .name = "tkill", .errmsg = true,
1137 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001138 { .name = "truncate", .errmsg = true,
1139 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001140 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001141 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001142 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1143 [1] = SCA_FILENAME, /* pathname */ }, },
1144 { .name = "utime", .errmsg = true,
1145 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001146 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001147 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1148 [1] = SCA_FILENAME, /* filename */ }, },
1149 { .name = "utimes", .errmsg = true,
1150 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001151 { .name = "vmsplice", .errmsg = true,
1152 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001153 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001154 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001155 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001156 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001157 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001158 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001159 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001160 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001161};
1162
1163static int syscall_fmt__cmp(const void *name, const void *fmtp)
1164{
1165 const struct syscall_fmt *fmt = fmtp;
1166 return strcmp(name, fmt->name);
1167}
1168
1169static struct syscall_fmt *syscall_fmt__find(const char *name)
1170{
1171 const int nmemb = ARRAY_SIZE(syscall_fmts);
1172 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1173}
1174
1175struct syscall {
1176 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001177 int nr_args;
1178 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001179 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001180 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001181 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001182 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001183 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001184};
1185
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001186static size_t fprintf_duration(unsigned long t, FILE *fp)
1187{
1188 double duration = (double)t / NSEC_PER_MSEC;
1189 size_t printed = fprintf(fp, "(");
1190
1191 if (duration >= 1.0)
1192 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1193 else if (duration >= 0.01)
1194 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1195 else
1196 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001197 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001198}
1199
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001200/**
1201 * filename.ptr: The filename char pointer that will be vfs_getname'd
1202 * filename.entry_str_pos: Where to insert the string translated from
1203 * filename.ptr by the vfs_getname tracepoint/kprobe.
1204 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001205struct thread_trace {
1206 u64 entry_time;
1207 u64 exit_time;
1208 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001209 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001210 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001211 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001212 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001213 struct {
1214 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001215 short int entry_str_pos;
1216 bool pending_open;
1217 unsigned int namelen;
1218 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001219 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001220 struct {
1221 int max;
1222 char **table;
1223 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001224
1225 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001226};
1227
1228static struct thread_trace *thread_trace__new(void)
1229{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001230 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1231
1232 if (ttrace)
1233 ttrace->paths.max = -1;
1234
David Ahernbf2575c2013-10-08 21:26:53 -06001235 ttrace->syscall_stats = intlist__new(NULL);
1236
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001237 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001238}
1239
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001240static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001241{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001242 struct thread_trace *ttrace;
1243
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001244 if (thread == NULL)
1245 goto fail;
1246
Namhyung Kim89dceb22014-10-06 09:46:03 +09001247 if (thread__priv(thread) == NULL)
1248 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001249
Namhyung Kim89dceb22014-10-06 09:46:03 +09001250 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001251 goto fail;
1252
Namhyung Kim89dceb22014-10-06 09:46:03 +09001253 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001254 ++ttrace->nr_events;
1255
1256 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001257fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001258 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001259 "WARNING: not enough memory, dropping samples!\n");
1260 return NULL;
1261}
1262
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001263#define TRACE_PFMAJ (1 << 0)
1264#define TRACE_PFMIN (1 << 1)
1265
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001266static const size_t trace__entry_str_size = 2048;
1267
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001268static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001269{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001270 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001271
1272 if (fd > ttrace->paths.max) {
1273 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1274
1275 if (npath == NULL)
1276 return -1;
1277
1278 if (ttrace->paths.max != -1) {
1279 memset(npath + ttrace->paths.max + 1, 0,
1280 (fd - ttrace->paths.max) * sizeof(char *));
1281 } else {
1282 memset(npath, 0, (fd + 1) * sizeof(char *));
1283 }
1284
1285 ttrace->paths.table = npath;
1286 ttrace->paths.max = fd;
1287 }
1288
1289 ttrace->paths.table[fd] = strdup(pathname);
1290
1291 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1292}
1293
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001294static int thread__read_fd_path(struct thread *thread, int fd)
1295{
1296 char linkname[PATH_MAX], pathname[PATH_MAX];
1297 struct stat st;
1298 int ret;
1299
1300 if (thread->pid_ == thread->tid) {
1301 scnprintf(linkname, sizeof(linkname),
1302 "/proc/%d/fd/%d", thread->pid_, fd);
1303 } else {
1304 scnprintf(linkname, sizeof(linkname),
1305 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1306 }
1307
1308 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1309 return -1;
1310
1311 ret = readlink(linkname, pathname, sizeof(pathname));
1312
1313 if (ret < 0 || ret > st.st_size)
1314 return -1;
1315
1316 pathname[ret] = '\0';
1317 return trace__set_fd_pathname(thread, fd, pathname);
1318}
1319
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001320static const char *thread__fd_path(struct thread *thread, int fd,
1321 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001322{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001323 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001324
1325 if (ttrace == NULL)
1326 return NULL;
1327
1328 if (fd < 0)
1329 return NULL;
1330
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001331 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001332 if (!trace->live)
1333 return NULL;
1334 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001335 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001336 return NULL;
1337 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001338
1339 return ttrace->paths.table[fd];
1340}
1341
1342static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1343 struct syscall_arg *arg)
1344{
1345 int fd = arg->val;
1346 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001347 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001348
1349 if (path)
1350 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1351
1352 return printed;
1353}
1354
1355static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1356 struct syscall_arg *arg)
1357{
1358 int fd = arg->val;
1359 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001360 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001361
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001362 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1363 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001364
1365 return printed;
1366}
1367
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001368static void thread__set_filename_pos(struct thread *thread, const char *bf,
1369 unsigned long ptr)
1370{
1371 struct thread_trace *ttrace = thread__priv(thread);
1372
1373 ttrace->filename.ptr = ptr;
1374 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1375}
1376
1377static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1378 struct syscall_arg *arg)
1379{
1380 unsigned long ptr = arg->val;
1381
1382 if (!arg->trace->vfs_getname)
1383 return scnprintf(bf, size, "%#x", ptr);
1384
1385 thread__set_filename_pos(arg->thread, bf, ptr);
1386 return 0;
1387}
1388
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001389static bool trace__filter_duration(struct trace *trace, double t)
1390{
1391 return t < (trace->duration_filter * NSEC_PER_MSEC);
1392}
1393
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001394static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1395{
1396 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1397
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001398 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001399}
1400
Namhyung Kimf15eb532012-10-05 14:02:16 +09001401static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001402static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001403
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001404static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001405{
1406 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001407 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001408}
1409
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001410static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001411 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001412{
1413 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001414 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001415
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001416 if (trace->multiple_threads) {
1417 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001418 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001419 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001420 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001421
1422 return printed;
1423}
1424
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001425static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001426 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001427{
1428 int ret = 0;
1429
1430 switch (event->header.type) {
1431 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001432 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001433 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001434 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001435 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001436 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001437 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001438 break;
1439 }
1440
1441 return ret;
1442}
1443
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001444static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001445 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001446 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001447 struct machine *machine)
1448{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001449 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001450 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001451}
1452
1453static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1454{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001455 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001456
1457 if (err)
1458 return err;
1459
David Ahern8fb598e2013-09-28 13:13:00 -06001460 trace->host = machine__new_host();
1461 if (trace->host == NULL)
1462 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001463
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001464 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001465 return -errno;
1466
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001467 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001468 evlist->threads, trace__tool_process, false,
1469 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001470 if (err)
1471 symbol__exit();
1472
1473 return err;
1474}
1475
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001476static int syscall__set_arg_fmts(struct syscall *sc)
1477{
1478 struct format_field *field;
1479 int idx = 0;
1480
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001481 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001482 if (sc->arg_scnprintf == NULL)
1483 return -1;
1484
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001485 if (sc->fmt)
1486 sc->arg_parm = sc->fmt->arg_parm;
1487
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001488 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001489 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1490 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1491 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001492 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001493 else if (strcmp(field->type, "pid_t") == 0)
1494 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001495 else if (strcmp(field->type, "umode_t") == 0)
1496 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001497 ++idx;
1498 }
1499
1500 return 0;
1501}
1502
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001503static int trace__read_syscall_info(struct trace *trace, int id)
1504{
1505 char tp_name[128];
1506 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001507 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001508
1509 if (name == NULL)
1510 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001511
1512 if (id > trace->syscalls.max) {
1513 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1514
1515 if (nsyscalls == NULL)
1516 return -1;
1517
1518 if (trace->syscalls.max != -1) {
1519 memset(nsyscalls + trace->syscalls.max + 1, 0,
1520 (id - trace->syscalls.max) * sizeof(*sc));
1521 } else {
1522 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1523 }
1524
1525 trace->syscalls.table = nsyscalls;
1526 trace->syscalls.max = id;
1527 }
1528
1529 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001530 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001531
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001532 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001533
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001534 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001535 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001536
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001537 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001538 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001539 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001540 }
1541
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001542 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001543 return -1;
1544
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001545 sc->args = sc->tp_format->format.fields;
1546 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001547 /*
1548 * We need to check and discard the first variable '__syscall_nr'
1549 * or 'nr' that mean the syscall number. It is needless here.
1550 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1551 */
1552 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001553 sc->args = sc->args->next;
1554 --sc->nr_args;
1555 }
1556
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001557 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1558
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001559 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001560}
1561
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001562static int trace__validate_ev_qualifier(struct trace *trace)
1563{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001564 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001565 struct str_node *pos;
1566
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001567 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1568 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1569 sizeof(trace->ev_qualifier_ids.entries[0]));
1570
1571 if (trace->ev_qualifier_ids.entries == NULL) {
1572 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1573 trace->output);
1574 err = -EINVAL;
1575 goto out;
1576 }
1577
1578 i = 0;
1579
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001580 strlist__for_each(pos, trace->ev_qualifier) {
1581 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001582 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001583
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001584 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001585 if (err == 0) {
1586 fputs("Error:\tInvalid syscall ", trace->output);
1587 err = -EINVAL;
1588 } else {
1589 fputs(", ", trace->output);
1590 }
1591
1592 fputs(sc, trace->output);
1593 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001594
1595 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001596 }
1597
1598 if (err < 0) {
1599 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1600 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001601 zfree(&trace->ev_qualifier_ids.entries);
1602 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001603 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001604out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001605 return err;
1606}
1607
David Ahern55d43bc2015-02-19 15:00:22 -05001608/*
1609 * args is to be interpreted as a series of longs but we need to handle
1610 * 8-byte unaligned accesses. args points to raw_data within the event
1611 * and raw_data is guaranteed to be 8-byte unaligned because it is
1612 * preceded by raw_size which is a u32. So we need to copy args to a temp
1613 * variable to read it. Most notably this avoids extended load instructions
1614 * on unaligned addresses
1615 */
1616
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001617static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001618 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001619 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001620{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001621 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001622 unsigned char *p;
1623 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001624
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001625 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001626 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001627 u8 bit = 1;
1628 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001629 .idx = 0,
1630 .mask = 0,
1631 .trace = trace,
1632 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001633 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001634
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001635 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001636 field = field->next, ++arg.idx, bit <<= 1) {
1637 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001638 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001639
1640 /* special care for unaligned accesses */
1641 p = args + sizeof(unsigned long) * arg.idx;
1642 memcpy(&val, p, sizeof(val));
1643
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001644 /*
1645 * Suppress this argument if its value is zero and
1646 * and we don't have a string associated in an
1647 * strarray for it.
1648 */
David Ahern55d43bc2015-02-19 15:00:22 -05001649 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001650 !(sc->arg_scnprintf &&
1651 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1652 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001653 continue;
1654
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001655 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001656 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001657 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001658 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001659 if (sc->arg_parm)
1660 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001661 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1662 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001663 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001664 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001665 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001666 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001667 }
1668 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001669 int i = 0;
1670
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001671 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001672 /* special care for unaligned accesses */
1673 p = args + sizeof(unsigned long) * i;
1674 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001675 printed += scnprintf(bf + printed, size - printed,
1676 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001677 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001678 ++i;
1679 }
1680 }
1681
1682 return printed;
1683}
1684
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001685typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001686 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001687 struct perf_sample *sample);
1688
1689static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001690 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001691{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001692
1693 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001694
1695 /*
1696 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1697 * before that, leaving at a higher verbosity level till that is
1698 * explained. Reproduced with plain ftrace with:
1699 *
1700 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1701 * grep "NR -1 " /t/trace_pipe
1702 *
1703 * After generating some load on the machine.
1704 */
1705 if (verbose > 1) {
1706 static u64 n;
1707 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1708 id, perf_evsel__name(evsel), ++n);
1709 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001710 return NULL;
1711 }
1712
1713 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1714 trace__read_syscall_info(trace, id))
1715 goto out_cant_read;
1716
1717 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1718 goto out_cant_read;
1719
1720 return &trace->syscalls.table[id];
1721
1722out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001723 if (verbose) {
1724 fprintf(trace->output, "Problems reading syscall %d", id);
1725 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1726 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1727 fputs(" information\n", trace->output);
1728 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001729 return NULL;
1730}
1731
David Ahernbf2575c2013-10-08 21:26:53 -06001732static void thread__update_stats(struct thread_trace *ttrace,
1733 int id, struct perf_sample *sample)
1734{
1735 struct int_node *inode;
1736 struct stats *stats;
1737 u64 duration = 0;
1738
1739 inode = intlist__findnew(ttrace->syscall_stats, id);
1740 if (inode == NULL)
1741 return;
1742
1743 stats = inode->priv;
1744 if (stats == NULL) {
1745 stats = malloc(sizeof(struct stats));
1746 if (stats == NULL)
1747 return;
1748 init_stats(stats);
1749 inode->priv = stats;
1750 }
1751
1752 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1753 duration = sample->time - ttrace->entry_time;
1754
1755 update_stats(stats, duration);
1756}
1757
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001758static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1759{
1760 struct thread_trace *ttrace;
1761 u64 duration;
1762 size_t printed;
1763
1764 if (trace->current == NULL)
1765 return 0;
1766
1767 ttrace = thread__priv(trace->current);
1768
1769 if (!ttrace->entry_pending)
1770 return 0;
1771
1772 duration = sample->time - ttrace->entry_time;
1773
1774 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1775 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1776 ttrace->entry_pending = false;
1777
1778 return printed;
1779}
1780
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001781static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001782 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001783 struct perf_sample *sample)
1784{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001785 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001786 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001787 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001788 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001789 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001790 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001791 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001792
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001793 if (sc == NULL)
1794 return -1;
1795
David Ahern8fb598e2013-09-28 13:13:00 -06001796 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001797 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001798 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001799 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001800
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001801 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001802
1803 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001804 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001805 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001806 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001807 }
1808
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001809 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001810 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001811
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001812 ttrace->entry_time = sample->time;
1813 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001814 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001815
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001816 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001817 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001818
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001819 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001820 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001821 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1822 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001823 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001824 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001825 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001826 /* See trace__vfs_getname & trace__sys_exit */
1827 ttrace->filename.pending_open = false;
1828 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001829
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001830 if (trace->current != thread) {
1831 thread__put(trace->current);
1832 trace->current = thread__get(thread);
1833 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001834 err = 0;
1835out_put:
1836 thread__put(thread);
1837 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001838}
1839
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001840static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1841 struct perf_sample *sample,
1842 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001843{
1844 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001845
1846 if (machine__resolve(trace->host, &al, sample) < 0 ||
1847 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1848 return -1;
1849
1850 return 0;
1851}
1852
1853static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1854{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001855 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001856 const unsigned int print_opts = EVSEL__PRINT_SYM |
1857 EVSEL__PRINT_DSO |
1858 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001859
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001860 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001861}
1862
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001863static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001864 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001865 struct perf_sample *sample)
1866{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001867 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001868 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001869 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001870 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001871 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001872 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001873
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001874 if (sc == NULL)
1875 return -1;
1876
David Ahern8fb598e2013-09-28 13:13:00 -06001877 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001878 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001879 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001880 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001881
David Ahernbf2575c2013-10-08 21:26:53 -06001882 if (trace->summary)
1883 thread__update_stats(ttrace, id, sample);
1884
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001885 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001886
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001887 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001888 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1889 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001890 ++trace->stats.vfs_getname;
1891 }
1892
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001893 ttrace->exit_time = sample->time;
1894
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001895 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001896 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001897 if (trace__filter_duration(trace, duration))
1898 goto out;
1899 } else if (trace->duration_filter)
1900 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001901
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001902 if (sample->callchain) {
1903 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1904 if (callchain_ret == 0) {
1905 if (callchain_cursor.nr < trace->min_stack)
1906 goto out;
1907 callchain_ret = 1;
1908 }
1909 }
1910
David Ahernfd2eaba2013-11-12 09:31:15 -07001911 if (trace->summary_only)
1912 goto out;
1913
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001914 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001915
1916 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001917 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001918 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001919 fprintf(trace->output, " ... [");
1920 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1921 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001922 }
1923
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001924 if (sc->fmt == NULL) {
1925signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001926 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001927 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001928 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001929 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1930 *e = audit_errno_to_name(-ret);
1931
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001932 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001933 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001934 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001935 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001936 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001937 else if (sc->fmt->errpid) {
1938 struct thread *child = machine__find_thread(trace->host, ret, ret);
1939
1940 if (child != NULL) {
1941 fprintf(trace->output, ") = %ld", ret);
1942 if (child->comm_set)
1943 fprintf(trace->output, " (%s)", thread__comm_str(child));
1944 thread__put(child);
1945 }
1946 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001947 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001948
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001949 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001950
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001951 if (callchain_ret > 0)
1952 trace__fprintf_callchain(trace, sample);
1953 else if (callchain_ret < 0)
1954 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001955out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001956 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001957 err = 0;
1958out_put:
1959 thread__put(thread);
1960 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001961}
1962
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001963static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001964 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001965 struct perf_sample *sample)
1966{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001967 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1968 struct thread_trace *ttrace;
1969 size_t filename_len, entry_str_len, to_move;
1970 ssize_t remaining_space;
1971 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001972 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001973
1974 if (!thread)
1975 goto out;
1976
1977 ttrace = thread__priv(thread);
1978 if (!ttrace)
1979 goto out;
1980
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001981 filename_len = strlen(filename);
1982
1983 if (ttrace->filename.namelen < filename_len) {
1984 char *f = realloc(ttrace->filename.name, filename_len + 1);
1985
1986 if (f == NULL)
1987 goto out;
1988
1989 ttrace->filename.namelen = filename_len;
1990 ttrace->filename.name = f;
1991 }
1992
1993 strcpy(ttrace->filename.name, filename);
1994 ttrace->filename.pending_open = true;
1995
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001996 if (!ttrace->filename.ptr)
1997 goto out;
1998
1999 entry_str_len = strlen(ttrace->entry_str);
2000 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2001 if (remaining_space <= 0)
2002 goto out;
2003
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002004 if (filename_len > (size_t)remaining_space) {
2005 filename += filename_len - remaining_space;
2006 filename_len = remaining_space;
2007 }
2008
2009 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2010 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2011 memmove(pos + filename_len, pos, to_move);
2012 memcpy(pos, filename, filename_len);
2013
2014 ttrace->filename.ptr = 0;
2015 ttrace->filename.entry_str_pos = 0;
2016out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002017 return 0;
2018}
2019
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002020static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002021 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002022 struct perf_sample *sample)
2023{
2024 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2025 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06002026 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03002027 sample->pid,
2028 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002029 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002030
2031 if (ttrace == NULL)
2032 goto out_dump;
2033
2034 ttrace->runtime_ms += runtime_ms;
2035 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002036 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002037 return 0;
2038
2039out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002040 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002041 evsel->name,
2042 perf_evsel__strval(evsel, sample, "comm"),
2043 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2044 runtime,
2045 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002046 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002047 return 0;
2048}
2049
Wang Nan1d6c9402016-02-26 09:31:55 +00002050static void bpf_output__printer(enum binary_printer_ops op,
2051 unsigned int val, void *extra)
2052{
2053 FILE *output = extra;
2054 unsigned char ch = (unsigned char)val;
2055
2056 switch (op) {
2057 case BINARY_PRINT_CHAR_DATA:
2058 fprintf(output, "%c", isprint(ch) ? ch : '.');
2059 break;
2060 case BINARY_PRINT_DATA_BEGIN:
2061 case BINARY_PRINT_LINE_BEGIN:
2062 case BINARY_PRINT_ADDR:
2063 case BINARY_PRINT_NUM_DATA:
2064 case BINARY_PRINT_NUM_PAD:
2065 case BINARY_PRINT_SEP:
2066 case BINARY_PRINT_CHAR_PAD:
2067 case BINARY_PRINT_LINE_END:
2068 case BINARY_PRINT_DATA_END:
2069 default:
2070 break;
2071 }
2072}
2073
2074static void bpf_output__fprintf(struct trace *trace,
2075 struct perf_sample *sample)
2076{
2077 print_binary(sample->raw_data, sample->raw_size, 8,
2078 bpf_output__printer, trace->output);
2079}
2080
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002081static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2082 union perf_event *event __maybe_unused,
2083 struct perf_sample *sample)
2084{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002085 int callchain_ret = 0;
2086
2087 if (sample->callchain) {
2088 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2089 if (callchain_ret == 0) {
2090 if (callchain_cursor.nr < trace->min_stack)
2091 goto out;
2092 callchain_ret = 1;
2093 }
2094 }
2095
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002096 trace__printf_interrupted_entry(trace, sample);
2097 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002098
2099 if (trace->trace_syscalls)
2100 fprintf(trace->output, "( ): ");
2101
2102 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002103
Wang Nan1d6c9402016-02-26 09:31:55 +00002104 if (perf_evsel__is_bpf_output(evsel)) {
2105 bpf_output__fprintf(trace, sample);
2106 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002107 event_format__fprintf(evsel->tp_format, sample->cpu,
2108 sample->raw_data, sample->raw_size,
2109 trace->output);
2110 }
2111
2112 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03002113
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002114 if (callchain_ret > 0)
2115 trace__fprintf_callchain(trace, sample);
2116 else if (callchain_ret < 0)
2117 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
2118out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002119 return 0;
2120}
2121
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002122static void print_location(FILE *f, struct perf_sample *sample,
2123 struct addr_location *al,
2124 bool print_dso, bool print_sym)
2125{
2126
2127 if ((verbose || print_dso) && al->map)
2128 fprintf(f, "%s@", al->map->dso->long_name);
2129
2130 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002131 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002132 al->addr - al->sym->start);
2133 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002134 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002135 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002136 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002137}
2138
2139static int trace__pgfault(struct trace *trace,
2140 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002141 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002142 struct perf_sample *sample)
2143{
2144 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002145 struct addr_location al;
2146 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002147 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002148 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002149 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002150
2151 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002152
2153 if (sample->callchain) {
2154 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2155 if (callchain_ret == 0) {
2156 if (callchain_cursor.nr < trace->min_stack)
2157 goto out_put;
2158 callchain_ret = 1;
2159 }
2160 }
2161
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002162 ttrace = thread__trace(thread, trace->output);
2163 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002164 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002165
2166 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2167 ttrace->pfmaj++;
2168 else
2169 ttrace->pfmin++;
2170
2171 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002172 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002173
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002174 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002175 sample->ip, &al);
2176
2177 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2178
2179 fprintf(trace->output, "%sfault [",
2180 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2181 "maj" : "min");
2182
2183 print_location(trace->output, sample, &al, false, true);
2184
2185 fprintf(trace->output, "] => ");
2186
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002187 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002188 sample->addr, &al);
2189
2190 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002191 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002192 MAP__FUNCTION, sample->addr, &al);
2193
2194 if (al.map)
2195 map_type = 'x';
2196 else
2197 map_type = '?';
2198 }
2199
2200 print_location(trace->output, sample, &al, true, false);
2201
2202 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002203
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002204 if (callchain_ret > 0)
2205 trace__fprintf_callchain(trace, sample);
2206 else if (callchain_ret < 0)
2207 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002208out:
2209 err = 0;
2210out_put:
2211 thread__put(thread);
2212 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002213}
2214
David Ahernbdc89662013-08-28 22:29:53 -06002215static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2216{
2217 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2218 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2219 return false;
2220
2221 if (trace->pid_list || trace->tid_list)
2222 return true;
2223
2224 return false;
2225}
2226
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002227static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002228 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002229 struct perf_sample *sample)
2230{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002231 /*
2232 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2233 * and don't use sample->time unconditionally, we may end up having
2234 * some other event in the future without PERF_SAMPLE_TIME for good
2235 * reason, i.e. we may not be interested in its timestamps, just in
2236 * it taking place, picking some piece of information when it
2237 * appears in our event stream (vfs_getname comes to mind).
2238 */
2239 if (trace->base_time == 0 && !trace->full_time &&
2240 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002241 trace->base_time = sample->time;
2242}
2243
David Ahern6810fc92013-08-28 22:29:52 -06002244static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002245 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002246 struct perf_sample *sample,
2247 struct perf_evsel *evsel,
2248 struct machine *machine __maybe_unused)
2249{
2250 struct trace *trace = container_of(tool, struct trace, tool);
2251 int err = 0;
2252
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002253 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002254
David Ahernbdc89662013-08-28 22:29:53 -06002255 if (skip_sample(trace, sample))
2256 return 0;
2257
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002258 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002259
David Ahern31605652013-12-04 19:41:41 -07002260 if (handler) {
2261 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002262 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002263 }
David Ahern6810fc92013-08-28 22:29:52 -06002264
2265 return err;
2266}
2267
David Ahernbdc89662013-08-28 22:29:53 -06002268static int parse_target_str(struct trace *trace)
2269{
2270 if (trace->opts.target.pid) {
2271 trace->pid_list = intlist__new(trace->opts.target.pid);
2272 if (trace->pid_list == NULL) {
2273 pr_err("Error parsing process id string\n");
2274 return -EINVAL;
2275 }
2276 }
2277
2278 if (trace->opts.target.tid) {
2279 trace->tid_list = intlist__new(trace->opts.target.tid);
2280 if (trace->tid_list == NULL) {
2281 pr_err("Error parsing thread id string\n");
2282 return -EINVAL;
2283 }
2284 }
2285
2286 return 0;
2287}
2288
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002289static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002290{
2291 unsigned int rec_argc, i, j;
2292 const char **rec_argv;
2293 const char * const record_args[] = {
2294 "record",
2295 "-R",
2296 "-m", "1024",
2297 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002298 };
2299
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002300 const char * const sc_args[] = { "-e", };
2301 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2302 const char * const majpf_args[] = { "-e", "major-faults" };
2303 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2304 const char * const minpf_args[] = { "-e", "minor-faults" };
2305 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2306
David Ahern9aca7f12013-12-04 19:41:39 -07002307 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002308 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2309 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002310 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2311
2312 if (rec_argv == NULL)
2313 return -ENOMEM;
2314
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002315 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002316 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002317 rec_argv[j++] = record_args[i];
2318
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002319 if (trace->trace_syscalls) {
2320 for (i = 0; i < sc_args_nr; i++)
2321 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002322
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002323 /* event string may be different for older kernels - e.g., RHEL6 */
2324 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2325 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2326 else if (is_valid_tracepoint("syscalls:sys_enter"))
2327 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2328 else {
2329 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2330 return -1;
2331 }
David Ahern9aca7f12013-12-04 19:41:39 -07002332 }
David Ahern9aca7f12013-12-04 19:41:39 -07002333
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002334 if (trace->trace_pgfaults & TRACE_PFMAJ)
2335 for (i = 0; i < majpf_args_nr; i++)
2336 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002337
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002338 if (trace->trace_pgfaults & TRACE_PFMIN)
2339 for (i = 0; i < minpf_args_nr; i++)
2340 rec_argv[j++] = minpf_args[i];
2341
2342 for (i = 0; i < (unsigned int)argc; i++)
2343 rec_argv[j++] = argv[i];
2344
2345 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002346}
2347
David Ahernbf2575c2013-10-08 21:26:53 -06002348static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2349
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002350static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002351{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002352 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002353
2354 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002355 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002356
2357 if (perf_evsel__field(evsel, "pathname") == NULL) {
2358 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002359 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002360 }
2361
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002362 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002363 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002364 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002365}
2366
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002367static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002368{
2369 struct perf_evsel *evsel;
2370 struct perf_event_attr attr = {
2371 .type = PERF_TYPE_SOFTWARE,
2372 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002373 };
2374
2375 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002376 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002377
2378 event_attr_init(&attr);
2379
2380 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002381 if (evsel)
2382 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002383
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002384 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002385}
2386
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002387static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2388{
2389 const u32 type = event->header.type;
2390 struct perf_evsel *evsel;
2391
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002392 if (type != PERF_RECORD_SAMPLE) {
2393 trace__process_event(trace, trace->host, event, sample);
2394 return;
2395 }
2396
2397 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2398 if (evsel == NULL) {
2399 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2400 return;
2401 }
2402
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002403 trace__set_base_time(trace, evsel, sample);
2404
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002405 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2406 sample->raw_data == NULL) {
2407 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2408 perf_evsel__name(evsel), sample->tid,
2409 sample->cpu, sample->raw_size);
2410 } else {
2411 tracepoint_handler handler = evsel->handler;
2412 handler(trace, evsel, event, sample);
2413 }
2414}
2415
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002416static int trace__add_syscall_newtp(struct trace *trace)
2417{
2418 int ret = -1;
2419 struct perf_evlist *evlist = trace->evlist;
2420 struct perf_evsel *sys_enter, *sys_exit;
2421
2422 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2423 if (sys_enter == NULL)
2424 goto out;
2425
2426 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2427 goto out_delete_sys_enter;
2428
2429 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2430 if (sys_exit == NULL)
2431 goto out_delete_sys_enter;
2432
2433 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2434 goto out_delete_sys_exit;
2435
2436 perf_evlist__add(evlist, sys_enter);
2437 perf_evlist__add(evlist, sys_exit);
2438
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002439 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002440 /*
2441 * We're interested only in the user space callchain
2442 * leading to the syscall, allow overriding that for
2443 * debugging reasons using --kernel_syscall_callchains
2444 */
2445 sys_exit->attr.exclude_callchain_kernel = 1;
2446 }
2447
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002448 trace->syscalls.events.sys_enter = sys_enter;
2449 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002450
2451 ret = 0;
2452out:
2453 return ret;
2454
2455out_delete_sys_exit:
2456 perf_evsel__delete_priv(sys_exit);
2457out_delete_sys_enter:
2458 perf_evsel__delete_priv(sys_enter);
2459 goto out;
2460}
2461
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002462static int trace__set_ev_qualifier_filter(struct trace *trace)
2463{
2464 int err = -1;
2465 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2466 trace->ev_qualifier_ids.nr,
2467 trace->ev_qualifier_ids.entries);
2468
2469 if (filter == NULL)
2470 goto out_enomem;
2471
2472 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2473 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2474
2475 free(filter);
2476out:
2477 return err;
2478out_enomem:
2479 errno = ENOMEM;
2480 goto out;
2481}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002482
Namhyung Kimf15eb532012-10-05 14:02:16 +09002483static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002484{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002485 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002486 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002487 int err = -1, i;
2488 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002489 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002490 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002491
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002492 trace->live = true;
2493
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002494 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002495 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002496
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002497 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002498 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002499
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002500 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2501 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2502 if (pgfault_maj == NULL)
2503 goto out_error_mem;
2504 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002505 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002506
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002507 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2508 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2509 if (pgfault_min == NULL)
2510 goto out_error_mem;
2511 perf_evlist__add(evlist, pgfault_min);
2512 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002513
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002514 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002515 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2516 trace__sched_stat_runtime))
2517 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002518
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002519 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2520 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002521 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002522 goto out_delete_evlist;
2523 }
2524
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002525 err = trace__symbols_init(trace, evlist);
2526 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002527 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002528 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002529 }
2530
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002531 perf_evlist__config(evlist, &trace->opts, NULL);
2532
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002533 if (callchain_param.enabled) {
2534 bool use_identifier = false;
2535
2536 if (trace->syscalls.events.sys_exit) {
2537 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2538 &trace->opts, &callchain_param);
2539 use_identifier = true;
2540 }
2541
2542 if (pgfault_maj) {
2543 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2544 use_identifier = true;
2545 }
2546
2547 if (pgfault_min) {
2548 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2549 use_identifier = true;
2550 }
2551
2552 if (use_identifier) {
2553 /*
2554 * Now we have evsels with different sample_ids, use
2555 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2556 * from a fixed position in each ring buffer record.
2557 *
2558 * As of this the changeset introducing this comment, this
2559 * isn't strictly needed, as the fields that can come before
2560 * PERF_SAMPLE_ID are all used, but we'll probably disable
2561 * some of those for things like copying the payload of
2562 * pointer syscall arguments, and for vfs_getname we don't
2563 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2564 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2565 */
2566 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2567 perf_evlist__reset_sample_bit(evlist, ID);
2568 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002569 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002570
Namhyung Kimf15eb532012-10-05 14:02:16 +09002571 signal(SIGCHLD, sig_handler);
2572 signal(SIGINT, sig_handler);
2573
2574 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002575 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002576 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002577 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002578 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002579 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002580 }
2581 }
2582
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002583 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002584 if (err < 0)
2585 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002586
Wang Nanba504232016-02-26 09:31:54 +00002587 err = bpf__apply_obj_config();
2588 if (err) {
2589 char errbuf[BUFSIZ];
2590
2591 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2592 pr_err("ERROR: Apply config to BPF failed: %s\n",
2593 errbuf);
2594 goto out_error_open;
2595 }
2596
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002597 /*
2598 * Better not use !target__has_task() here because we need to cover the
2599 * case where no threads were specified in the command line, but a
2600 * workload was, and in that case we will fill in the thread_map when
2601 * we fork the workload in perf_evlist__prepare_workload.
2602 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002603 if (trace->filter_pids.nr > 0)
2604 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002605 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002606 err = perf_evlist__set_filter_pid(evlist, getpid());
2607
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002608 if (err < 0)
2609 goto out_error_mem;
2610
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002611 if (trace->ev_qualifier_ids.nr > 0) {
2612 err = trace__set_ev_qualifier_filter(trace);
2613 if (err < 0)
2614 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002615
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002616 pr_debug("event qualifier tracepoint filter: %s\n",
2617 trace->syscalls.events.sys_exit->filter);
2618 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002619
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002620 err = perf_evlist__apply_filters(evlist, &evsel);
2621 if (err < 0)
2622 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002623
Jiri Olsaf8850372013-11-28 17:57:22 +01002624 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002625 if (err < 0)
2626 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002627
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002628 if (!target__none(&trace->opts.target))
2629 perf_evlist__enable(evlist);
2630
Namhyung Kimf15eb532012-10-05 14:02:16 +09002631 if (forks)
2632 perf_evlist__start_workload(evlist);
2633
Jiri Olsae13798c2015-06-23 00:36:02 +02002634 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002635 evlist->threads->nr > 1 ||
2636 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002637again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002638 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002639
2640 for (i = 0; i < evlist->nr_mmaps; i++) {
2641 union perf_event *event;
2642
2643 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002644 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002645
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002646 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002647
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002648 err = perf_evlist__parse_sample(evlist, event, &sample);
2649 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002650 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002651 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002652 }
2653
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002654 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002655next_event:
2656 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002657
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002658 if (interrupted)
2659 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002660
2661 if (done && !draining) {
2662 perf_evlist__disable(evlist);
2663 draining = true;
2664 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002665 }
2666 }
2667
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002668 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002669 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002670
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002671 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2672 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2673 draining = true;
2674
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002675 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002676 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002677 } else {
2678 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002679 }
2680
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002681out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002682 thread__zput(trace->current);
2683
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002684 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002685
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002686 if (!err) {
2687 if (trace->summary)
2688 trace__fprintf_thread_summary(trace, trace->output);
2689
2690 if (trace->show_tool_stats) {
2691 fprintf(trace->output, "Stats:\n "
2692 " vfs_getname : %" PRIu64 "\n"
2693 " proc_getname: %" PRIu64 "\n",
2694 trace->stats.vfs_getname,
2695 trace->stats.proc_getname);
2696 }
2697 }
David Ahernbf2575c2013-10-08 21:26:53 -06002698
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002699out_delete_evlist:
2700 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002701 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002702 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002703 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002704{
2705 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002706
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002707out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002708 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002709 goto out_error;
2710
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002711out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002712 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002713 goto out_error;
2714
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002715out_error_mmap:
2716 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2717 goto out_error;
2718
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002719out_error_open:
2720 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2721
2722out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002723 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302724 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002725
2726out_error_apply_filters:
2727 fprintf(trace->output,
2728 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2729 evsel->filter, perf_evsel__name(evsel), errno,
2730 strerror_r(errno, errbuf, sizeof(errbuf)));
2731 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002732}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002733out_error_mem:
2734 fprintf(trace->output, "Not enough memory to run!\n");
2735 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002736
2737out_errno:
2738 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2739 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002740}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002741
David Ahern6810fc92013-08-28 22:29:52 -06002742static int trace__replay(struct trace *trace)
2743{
2744 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002745 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002746 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002747 struct perf_data_file file = {
2748 .path = input_name,
2749 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002750 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002751 };
David Ahern6810fc92013-08-28 22:29:52 -06002752 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002753 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002754 int err = -1;
2755
2756 trace->tool.sample = trace__process_sample;
2757 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002758 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002759 trace->tool.comm = perf_event__process_comm;
2760 trace->tool.exit = perf_event__process_exit;
2761 trace->tool.fork = perf_event__process_fork;
2762 trace->tool.attr = perf_event__process_attr;
2763 trace->tool.tracing_data = perf_event__process_tracing_data;
2764 trace->tool.build_id = perf_event__process_build_id;
2765
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002766 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002767 trace->tool.ordering_requires_timestamps = true;
2768
2769 /* add tid to output */
2770 trace->multiple_threads = true;
2771
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002772 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002773 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002774 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002775
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002776 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002777 goto out;
2778
David Ahern8fb598e2013-09-28 13:13:00 -06002779 trace->host = &session->machines.host;
2780
David Ahern6810fc92013-08-28 22:29:52 -06002781 err = perf_session__set_tracepoints_handlers(session, handlers);
2782 if (err)
2783 goto out;
2784
Namhyung Kim003824e2013-11-12 15:25:00 +09002785 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2786 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002787 /* older kernels have syscalls tp versus raw_syscalls */
2788 if (evsel == NULL)
2789 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2790 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002791
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002792 if (evsel &&
2793 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2794 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002795 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2796 goto out;
2797 }
2798
2799 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2800 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002801 if (evsel == NULL)
2802 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2803 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002804 if (evsel &&
2805 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2806 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002807 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002808 goto out;
2809 }
2810
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002811 evlist__for_each(session->evlist, evsel) {
2812 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2813 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2814 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2815 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2816 evsel->handler = trace__pgfault;
2817 }
2818
David Ahernbdc89662013-08-28 22:29:53 -06002819 err = parse_target_str(trace);
2820 if (err != 0)
2821 goto out;
2822
David Ahern6810fc92013-08-28 22:29:52 -06002823 setup_pager();
2824
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002825 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002826 if (err)
2827 pr_err("Failed to process events, error %d", err);
2828
David Ahernbf2575c2013-10-08 21:26:53 -06002829 else if (trace->summary)
2830 trace__fprintf_thread_summary(trace, trace->output);
2831
David Ahern6810fc92013-08-28 22:29:52 -06002832out:
2833 perf_session__delete(session);
2834
2835 return err;
2836}
2837
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002838static size_t trace__fprintf_threads_header(FILE *fp)
2839{
2840 size_t printed;
2841
Pekka Enberg99ff7152013-11-12 16:42:14 +02002842 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002843
2844 return printed;
2845}
2846
2847static size_t thread__dump_stats(struct thread_trace *ttrace,
2848 struct trace *trace, FILE *fp)
2849{
2850 struct stats *stats;
2851 size_t printed = 0;
2852 struct syscall *sc;
2853 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2854
2855 if (inode == NULL)
2856 return 0;
2857
2858 printed += fprintf(fp, "\n");
2859
Milian Wolff834fd462015-08-06 11:24:29 +02002860 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2861 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2862 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002863
David Ahernbf2575c2013-10-08 21:26:53 -06002864 /* each int_node is a syscall */
2865 while (inode) {
2866 stats = inode->priv;
2867 if (stats) {
2868 double min = (double)(stats->min) / NSEC_PER_MSEC;
2869 double max = (double)(stats->max) / NSEC_PER_MSEC;
2870 double avg = avg_stats(stats);
2871 double pct;
2872 u64 n = (u64) stats->n;
2873
2874 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2875 avg /= NSEC_PER_MSEC;
2876
2877 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002878 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002879 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
2880 n, avg * n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002881 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002882 }
2883
2884 inode = intlist__next(inode);
2885 }
2886
2887 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002888
2889 return printed;
2890}
2891
David Ahern896cbb52013-09-28 13:12:59 -06002892/* struct used to pass data to per-thread function */
2893struct summary_data {
2894 FILE *fp;
2895 struct trace *trace;
2896 size_t printed;
2897};
2898
2899static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2900{
2901 struct summary_data *data = priv;
2902 FILE *fp = data->fp;
2903 size_t printed = data->printed;
2904 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002905 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002906 double ratio;
2907
2908 if (ttrace == NULL)
2909 return 0;
2910
2911 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2912
Pekka Enberg15e65c62013-11-14 18:43:30 +02002913 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002914 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002915 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002916 if (ttrace->pfmaj)
2917 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2918 if (ttrace->pfmin)
2919 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002920 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002921 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002922
2923 data->printed += printed;
2924
2925 return 0;
2926}
2927
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002928static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2929{
David Ahern896cbb52013-09-28 13:12:59 -06002930 struct summary_data data = {
2931 .fp = fp,
2932 .trace = trace
2933 };
2934 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002935
David Ahern896cbb52013-09-28 13:12:59 -06002936 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002937
David Ahern896cbb52013-09-28 13:12:59 -06002938 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002939}
2940
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002941static int trace__set_duration(const struct option *opt, const char *str,
2942 int unset __maybe_unused)
2943{
2944 struct trace *trace = opt->value;
2945
2946 trace->duration_filter = atof(str);
2947 return 0;
2948}
2949
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002950static int trace__set_filter_pids(const struct option *opt, const char *str,
2951 int unset __maybe_unused)
2952{
2953 int ret = -1;
2954 size_t i;
2955 struct trace *trace = opt->value;
2956 /*
2957 * FIXME: introduce a intarray class, plain parse csv and create a
2958 * { int nr, int entries[] } struct...
2959 */
2960 struct intlist *list = intlist__new(str);
2961
2962 if (list == NULL)
2963 return -1;
2964
2965 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2966 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2967
2968 if (trace->filter_pids.entries == NULL)
2969 goto out;
2970
2971 trace->filter_pids.entries[0] = getpid();
2972
2973 for (i = 1; i < trace->filter_pids.nr; ++i)
2974 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2975
2976 intlist__delete(list);
2977 ret = 0;
2978out:
2979 return ret;
2980}
2981
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002982static int trace__open_output(struct trace *trace, const char *filename)
2983{
2984 struct stat st;
2985
2986 if (!stat(filename, &st) && st.st_size) {
2987 char oldname[PATH_MAX];
2988
2989 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2990 unlink(oldname);
2991 rename(filename, oldname);
2992 }
2993
2994 trace->output = fopen(filename, "w");
2995
2996 return trace->output == NULL ? -errno : 0;
2997}
2998
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002999static int parse_pagefaults(const struct option *opt, const char *str,
3000 int unset __maybe_unused)
3001{
3002 int *trace_pgfaults = opt->value;
3003
3004 if (strcmp(str, "all") == 0)
3005 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
3006 else if (strcmp(str, "maj") == 0)
3007 *trace_pgfaults |= TRACE_PFMAJ;
3008 else if (strcmp(str, "min") == 0)
3009 *trace_pgfaults |= TRACE_PFMIN;
3010 else
3011 return -1;
3012
3013 return 0;
3014}
3015
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003016static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3017{
3018 struct perf_evsel *evsel;
3019
3020 evlist__for_each(evlist, evsel)
3021 evsel->handler = handler;
3022}
3023
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003024int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3025{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003026 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003027 "perf trace [<options>] [<command>]",
3028 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003029 "perf trace record [<options>] [<command>]",
3030 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003031 NULL
3032 };
3033 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003034 .syscalls = {
3035 . max = -1,
3036 },
3037 .opts = {
3038 .target = {
3039 .uid = UINT_MAX,
3040 .uses_mmap = true,
3041 },
3042 .user_freq = UINT_MAX,
3043 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003044 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003045 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003046 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003047 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003048 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003049 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003050 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003051 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003052 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003053 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003054 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003055 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003056 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003057 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3058 "event selector. use 'perf list' to list available events",
3059 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003060 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3061 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003062 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03003063 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003064 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003065 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003066 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3067 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003068 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003069 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003070 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3071 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003072 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003073 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003074 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003075 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003076 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003077 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003078 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3079 "number of mmap data pages",
3080 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003081 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003082 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003083 OPT_CALLBACK(0, "duration", &trace, "float",
3084 "show only events with duration > N.M ms",
3085 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003086 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003087 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003088 OPT_BOOLEAN('T', "time", &trace.full_time,
3089 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003090 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3091 "Show only syscall summary with statistics"),
3092 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3093 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003094 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3095 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003096 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003097 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003098 OPT_CALLBACK(0, "call-graph", &trace.opts,
3099 "record_mode[,record_size]", record_callchain_help,
3100 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003101 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3102 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03003103 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3104 "Set the minimum stack depth when parsing the callchain, "
3105 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03003106 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3107 "Set the maximum stack depth when parsing the callchain, "
3108 "anything beyond the specified depth will be ignored. "
3109 "Default: " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04003110 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3111 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003112 OPT_END()
3113 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003114 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003115 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003116 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003117 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003118 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003119
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003120 signal(SIGSEGV, sighandler_dump_stack);
3121 signal(SIGFPE, sighandler_dump_stack);
3122
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003123 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003124 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003125
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003126 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003127 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003128 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003129 goto out;
3130 }
3131
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003132 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3133 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003134
Wang Nand7888572016-04-08 15:07:24 +00003135 err = bpf__setup_stdout(trace.evlist);
3136 if (err) {
3137 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3138 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3139 goto out;
3140 }
3141
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003142 err = -1;
3143
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003144 if (trace.trace_pgfaults) {
3145 trace.opts.sample_address = true;
3146 trace.opts.sample_time = true;
3147 }
3148
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003149 if (trace.opts.mmap_pages == UINT_MAX)
3150 mmap_pages_user_set = false;
3151
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003152 if (trace.max_stack == UINT_MAX) {
3153 trace.max_stack = PERF_MAX_STACK_DEPTH;
3154 max_stack_user_set = false;
3155 }
3156
3157#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003158 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003159 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
3160#endif
3161
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003162 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003163 if (!mmap_pages_user_set && geteuid() == 0)
3164 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3165
Milian Wolff566a0882016-04-08 13:34:15 +02003166 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003167 }
Milian Wolff566a0882016-04-08 13:34:15 +02003168
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003169 if (trace.evlist->nr_entries > 0)
3170 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3171
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003172 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3173 return trace__record(&trace, argc-1, &argv[1]);
3174
3175 /* summary_only implies summary option, but don't overwrite summary if set */
3176 if (trace.summary_only)
3177 trace.summary = trace.summary_only;
3178
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003179 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3180 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003181 pr_err("Please specify something to trace.\n");
3182 return -1;
3183 }
3184
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003185 if (!trace.trace_syscalls && ev_qualifier_str) {
3186 pr_err("The -e option can't be used with --no-syscalls.\n");
3187 goto out;
3188 }
3189
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003190 if (output_name != NULL) {
3191 err = trace__open_output(&trace, output_name);
3192 if (err < 0) {
3193 perror("failed to create output file");
3194 goto out;
3195 }
3196 }
3197
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003198 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3199
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003200 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003201 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03003202 struct strlist_config slist_config = {
3203 .dirname = system_path(STRACE_GROUPS_DIR),
3204 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003205
3206 trace.not_ev_qualifier = *s == '!';
3207 if (trace.not_ev_qualifier)
3208 ++s;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03003209 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003210 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003211 fputs("Not enough memory to parse event qualifier",
3212 trace.output);
3213 err = -ENOMEM;
3214 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003215 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003216
3217 err = trace__validate_ev_qualifier(&trace);
3218 if (err)
3219 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003220 }
3221
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003222 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003223 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003224 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003225 fprintf(trace.output, "%s", bf);
3226 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003227 }
3228
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003229 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003230 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003231 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003232 fprintf(trace.output, "%s", bf);
3233 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003234 }
3235
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003236 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003237 trace.opts.target.system_wide = true;
3238
David Ahern6810fc92013-08-28 22:29:52 -06003239 if (input_name)
3240 err = trace__replay(&trace);
3241 else
3242 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003243
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003244out_close:
3245 if (output_name != NULL)
3246 fclose(trace.output);
3247out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003248 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003249}