blob: fc276d718172008e682118a5e1f71c44ff08edc1 [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 Meloa1c25522015-06-11 22:47:54 -030059#ifndef PERF_FLAG_FD_NO_GROUP
60# define PERF_FLAG_FD_NO_GROUP (1UL << 0)
61#endif
62
63#ifndef PERF_FLAG_FD_OUTPUT
64# define PERF_FLAG_FD_OUTPUT (1UL << 1)
65#endif
66
67#ifndef PERF_FLAG_PID_CGROUP
68# define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */
69#endif
70
71#ifndef PERF_FLAG_FD_CLOEXEC
72# define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */
73#endif
74
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030075struct trace {
76 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030077 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030078 struct {
79 int max;
80 struct syscall *table;
81 struct {
82 struct perf_evsel *sys_enter,
83 *sys_exit;
84 } events;
85 } syscalls;
86 struct record_opts opts;
87 struct perf_evlist *evlist;
88 struct machine *host;
89 struct thread *current;
90 u64 base_time;
91 FILE *output;
92 unsigned long nr_events;
93 struct strlist *ev_qualifier;
94 struct {
95 size_t nr;
96 int *entries;
97 } ev_qualifier_ids;
98 struct intlist *tid_list;
99 struct intlist *pid_list;
100 struct {
101 size_t nr;
102 pid_t *entries;
103 } filter_pids;
104 double duration_filter;
105 double runtime_ms;
106 struct {
107 u64 vfs_getname,
108 proc_getname;
109 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -0300110 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -0300111 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300112 bool not_ev_qualifier;
113 bool live;
114 bool full_time;
115 bool sched;
116 bool multiple_threads;
117 bool summary;
118 bool summary_only;
119 bool show_comm;
120 bool show_tool_stats;
121 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300122 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300123 bool force;
124 bool vfs_getname;
125 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300126 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300127};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300128
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300129struct tp_field {
130 int offset;
131 union {
132 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
133 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
134 };
135};
136
137#define TP_UINT_FIELD(bits) \
138static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
139{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500140 u##bits value; \
141 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
142 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300143}
144
145TP_UINT_FIELD(8);
146TP_UINT_FIELD(16);
147TP_UINT_FIELD(32);
148TP_UINT_FIELD(64);
149
150#define TP_UINT_FIELD__SWAPPED(bits) \
151static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
152{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500153 u##bits value; \
154 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300155 return bswap_##bits(value);\
156}
157
158TP_UINT_FIELD__SWAPPED(16);
159TP_UINT_FIELD__SWAPPED(32);
160TP_UINT_FIELD__SWAPPED(64);
161
162static int tp_field__init_uint(struct tp_field *field,
163 struct format_field *format_field,
164 bool needs_swap)
165{
166 field->offset = format_field->offset;
167
168 switch (format_field->size) {
169 case 1:
170 field->integer = tp_field__u8;
171 break;
172 case 2:
173 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
174 break;
175 case 4:
176 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
177 break;
178 case 8:
179 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
180 break;
181 default:
182 return -1;
183 }
184
185 return 0;
186}
187
188static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
189{
190 return sample->raw_data + field->offset;
191}
192
193static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
194{
195 field->offset = format_field->offset;
196 field->pointer = tp_field__ptr;
197 return 0;
198}
199
200struct syscall_tp {
201 struct tp_field id;
202 union {
203 struct tp_field args, ret;
204 };
205};
206
207static int perf_evsel__init_tp_uint_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_uint(field, format_field, evsel->needs_swap);
217}
218
219#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
220 ({ struct syscall_tp *sc = evsel->priv;\
221 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
222
223static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
224 struct tp_field *field,
225 const char *name)
226{
227 struct format_field *format_field = perf_evsel__field(evsel, name);
228
229 if (format_field == NULL)
230 return -1;
231
232 return tp_field__init_ptr(field, format_field);
233}
234
235#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
236 ({ struct syscall_tp *sc = evsel->priv;\
237 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
238
239static void perf_evsel__delete_priv(struct perf_evsel *evsel)
240{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300241 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300242 perf_evsel__delete(evsel);
243}
244
Namhyung Kim96695d42013-11-12 08:51:45 -0300245static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
246{
247 evsel->priv = malloc(sizeof(struct syscall_tp));
248 if (evsel->priv != NULL) {
249 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
250 goto out_delete;
251
252 evsel->handler = handler;
253 return 0;
254 }
255
256 return -ENOMEM;
257
258out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300259 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300260 return -ENOENT;
261}
262
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300263static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300264{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300265 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300266
David Ahern9aca7f12013-12-04 19:41:39 -0700267 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200268 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700269 evsel = perf_evsel__newtp("syscalls", direction);
270
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200271 if (IS_ERR(evsel))
272 return NULL;
273
274 if (perf_evsel__init_syscall_tp(evsel, handler))
275 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300276
277 return evsel;
278
279out_delete:
280 perf_evsel__delete_priv(evsel);
281 return NULL;
282}
283
284#define perf_evsel__sc_tp_uint(evsel, name, sample) \
285 ({ struct syscall_tp *fields = evsel->priv; \
286 fields->name.integer(&fields->name, sample); })
287
288#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
289 ({ struct syscall_tp *fields = evsel->priv; \
290 fields->name.pointer(&fields->name, sample); })
291
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300292struct syscall_arg {
293 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300294 struct thread *thread;
295 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300296 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300297 u8 idx;
298 u8 mask;
299};
300
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300301struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300302 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300303 int nr_entries;
304 const char **entries;
305};
306
307#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
308 .nr_entries = ARRAY_SIZE(array), \
309 .entries = array, \
310}
311
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300312#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
313 .offset = off, \
314 .nr_entries = ARRAY_SIZE(array), \
315 .entries = array, \
316}
317
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300318static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
319 const char *intfmt,
320 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300321{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300322 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300323 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300324
325 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300326 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300327
328 return scnprintf(bf, size, "%s", sa->entries[idx]);
329}
330
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300331static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
332 struct syscall_arg *arg)
333{
334 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
335}
336
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300337#define SCA_STRARRAY syscall_arg__scnprintf_strarray
338
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300339#if defined(__i386__) || defined(__x86_64__)
340/*
341 * FIXME: Make this available to all arches as soon as the ioctl beautifier
342 * gets rewritten to support all arches.
343 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300344static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
345 struct syscall_arg *arg)
346{
347 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
348}
349
350#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300351#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300352
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300353static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
354 struct syscall_arg *arg);
355
356#define SCA_FD syscall_arg__scnprintf_fd
357
358static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
359 struct syscall_arg *arg)
360{
361 int fd = arg->val;
362
363 if (fd == AT_FDCWD)
364 return scnprintf(bf, size, "CWD");
365
366 return syscall_arg__scnprintf_fd(bf, size, arg);
367}
368
369#define SCA_FDAT syscall_arg__scnprintf_fd_at
370
371static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
372 struct syscall_arg *arg);
373
374#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
375
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300376static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300377 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300378{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300379 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300380}
381
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300382#define SCA_HEX syscall_arg__scnprintf_hex
383
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300384static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
385 struct syscall_arg *arg)
386{
387 return scnprintf(bf, size, "%d", arg->val);
388}
389
390#define SCA_INT syscall_arg__scnprintf_int
391
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300392static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
393 struct syscall_arg *arg)
394{
395 int printed = 0, op = arg->val;
396
397 if (op == 0)
398 return scnprintf(bf, size, "NONE");
399#define P_CMD(cmd) \
400 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
401 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
402 op &= ~LOCK_##cmd; \
403 }
404
405 P_CMD(SH);
406 P_CMD(EX);
407 P_CMD(NB);
408 P_CMD(UN);
409 P_CMD(MAND);
410 P_CMD(RW);
411 P_CMD(READ);
412 P_CMD(WRITE);
413#undef P_OP
414
415 if (op)
416 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
417
418 return printed;
419}
420
421#define SCA_FLOCK syscall_arg__scnprintf_flock
422
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300423static 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 -0300424{
425 enum syscall_futex_args {
426 SCF_UADDR = (1 << 0),
427 SCF_OP = (1 << 1),
428 SCF_VAL = (1 << 2),
429 SCF_TIMEOUT = (1 << 3),
430 SCF_UADDR2 = (1 << 4),
431 SCF_VAL3 = (1 << 5),
432 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300433 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300434 int cmd = op & FUTEX_CMD_MASK;
435 size_t printed = 0;
436
437 switch (cmd) {
438#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300439 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
440 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
441 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
442 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
443 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
444 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300445 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300446 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
447 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
448 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
449 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
450 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300451 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
452 default: printed = scnprintf(bf, size, "%#x", cmd); break;
453 }
454
455 if (op & FUTEX_PRIVATE_FLAG)
456 printed += scnprintf(bf + printed, size - printed, "|PRIV");
457
458 if (op & FUTEX_CLOCK_REALTIME)
459 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
460
461 return printed;
462}
463
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300464#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
465
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300466static const char *bpf_cmd[] = {
467 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
468 "MAP_GET_NEXT_KEY", "PROG_LOAD",
469};
470static DEFINE_STRARRAY(bpf_cmd);
471
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300472static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
473static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300474
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300475static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
476static DEFINE_STRARRAY(itimers);
477
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300478static const char *keyctl_options[] = {
479 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
480 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
481 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
482 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
483 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
484};
485static DEFINE_STRARRAY(keyctl_options);
486
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300487static const char *whences[] = { "SET", "CUR", "END",
488#ifdef SEEK_DATA
489"DATA",
490#endif
491#ifdef SEEK_HOLE
492"HOLE",
493#endif
494};
495static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300496
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300497static const char *fcntl_cmds[] = {
498 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
499 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
500 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
501 "F_GETOWNER_UIDS",
502};
503static DEFINE_STRARRAY(fcntl_cmds);
504
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300505static const char *rlimit_resources[] = {
506 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
507 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
508 "RTTIME",
509};
510static DEFINE_STRARRAY(rlimit_resources);
511
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300512static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
513static DEFINE_STRARRAY(sighow);
514
David Ahern4f8c1b72013-09-22 19:45:00 -0600515static const char *clockid[] = {
516 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300517 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
518 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600519};
520static DEFINE_STRARRAY(clockid);
521
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300522static const char *socket_families[] = {
523 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
524 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
525 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
526 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
527 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
528 "ALG", "NFC", "VSOCK",
529};
530static DEFINE_STRARRAY(socket_families);
531
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300532#ifndef MSG_PROBE
533#define MSG_PROBE 0x10
534#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600535#ifndef MSG_WAITFORONE
536#define MSG_WAITFORONE 0x10000
537#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300538#ifndef MSG_SENDPAGE_NOTLAST
539#define MSG_SENDPAGE_NOTLAST 0x20000
540#endif
541#ifndef MSG_FASTOPEN
542#define MSG_FASTOPEN 0x20000000
543#endif
544
545static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
546 struct syscall_arg *arg)
547{
548 int printed = 0, flags = arg->val;
549
550 if (flags == 0)
551 return scnprintf(bf, size, "NONE");
552#define P_MSG_FLAG(n) \
553 if (flags & MSG_##n) { \
554 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
555 flags &= ~MSG_##n; \
556 }
557
558 P_MSG_FLAG(OOB);
559 P_MSG_FLAG(PEEK);
560 P_MSG_FLAG(DONTROUTE);
561 P_MSG_FLAG(TRYHARD);
562 P_MSG_FLAG(CTRUNC);
563 P_MSG_FLAG(PROBE);
564 P_MSG_FLAG(TRUNC);
565 P_MSG_FLAG(DONTWAIT);
566 P_MSG_FLAG(EOR);
567 P_MSG_FLAG(WAITALL);
568 P_MSG_FLAG(FIN);
569 P_MSG_FLAG(SYN);
570 P_MSG_FLAG(CONFIRM);
571 P_MSG_FLAG(RST);
572 P_MSG_FLAG(ERRQUEUE);
573 P_MSG_FLAG(NOSIGNAL);
574 P_MSG_FLAG(MORE);
575 P_MSG_FLAG(WAITFORONE);
576 P_MSG_FLAG(SENDPAGE_NOTLAST);
577 P_MSG_FLAG(FASTOPEN);
578 P_MSG_FLAG(CMSG_CLOEXEC);
579#undef P_MSG_FLAG
580
581 if (flags)
582 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
583
584 return printed;
585}
586
587#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
588
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300589static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
590 struct syscall_arg *arg)
591{
592 size_t printed = 0;
593 int mode = arg->val;
594
595 if (mode == F_OK) /* 0 */
596 return scnprintf(bf, size, "F");
597#define P_MODE(n) \
598 if (mode & n##_OK) { \
599 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
600 mode &= ~n##_OK; \
601 }
602
603 P_MODE(R);
604 P_MODE(W);
605 P_MODE(X);
606#undef P_MODE
607
608 if (mode)
609 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
610
611 return printed;
612}
613
614#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
615
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300616static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
617 struct syscall_arg *arg);
618
619#define SCA_FILENAME syscall_arg__scnprintf_filename
620
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300621static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300622 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300623{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300624 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300625
626 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300627 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300628
629 if (flags == 0)
630 return scnprintf(bf, size, "RDONLY");
631#define P_FLAG(n) \
632 if (flags & O_##n) { \
633 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
634 flags &= ~O_##n; \
635 }
636
637 P_FLAG(APPEND);
638 P_FLAG(ASYNC);
639 P_FLAG(CLOEXEC);
640 P_FLAG(CREAT);
641 P_FLAG(DIRECT);
642 P_FLAG(DIRECTORY);
643 P_FLAG(EXCL);
644 P_FLAG(LARGEFILE);
645 P_FLAG(NOATIME);
646 P_FLAG(NOCTTY);
647#ifdef O_NONBLOCK
648 P_FLAG(NONBLOCK);
649#elif O_NDELAY
650 P_FLAG(NDELAY);
651#endif
652#ifdef O_PATH
653 P_FLAG(PATH);
654#endif
655 P_FLAG(RDWR);
656#ifdef O_DSYNC
657 if ((flags & O_SYNC) == O_SYNC)
658 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
659 else {
660 P_FLAG(DSYNC);
661 }
662#else
663 P_FLAG(SYNC);
664#endif
665 P_FLAG(TRUNC);
666 P_FLAG(WRONLY);
667#undef P_FLAG
668
669 if (flags)
670 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
671
672 return printed;
673}
674
675#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
676
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300677static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size,
678 struct syscall_arg *arg)
679{
680 int printed = 0, flags = arg->val;
681
682 if (flags == 0)
683 return 0;
684
685#define P_FLAG(n) \
686 if (flags & PERF_FLAG_##n) { \
687 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
688 flags &= ~PERF_FLAG_##n; \
689 }
690
691 P_FLAG(FD_NO_GROUP);
692 P_FLAG(FD_OUTPUT);
693 P_FLAG(PID_CGROUP);
694 P_FLAG(FD_CLOEXEC);
695#undef P_FLAG
696
697 if (flags)
698 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
699
700 return printed;
701}
702
703#define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags
704
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300705static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
706 struct syscall_arg *arg)
707{
708 int printed = 0, flags = arg->val;
709
710#define P_FLAG(n) \
711 if (flags & O_##n) { \
712 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
713 flags &= ~O_##n; \
714 }
715
716 P_FLAG(CLOEXEC);
717 P_FLAG(NONBLOCK);
718#undef P_FLAG
719
720 if (flags)
721 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
722
723 return printed;
724}
725
726#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
727
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300728static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
729{
730 int sig = arg->val;
731
732 switch (sig) {
733#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
734 P_SIGNUM(HUP);
735 P_SIGNUM(INT);
736 P_SIGNUM(QUIT);
737 P_SIGNUM(ILL);
738 P_SIGNUM(TRAP);
739 P_SIGNUM(ABRT);
740 P_SIGNUM(BUS);
741 P_SIGNUM(FPE);
742 P_SIGNUM(KILL);
743 P_SIGNUM(USR1);
744 P_SIGNUM(SEGV);
745 P_SIGNUM(USR2);
746 P_SIGNUM(PIPE);
747 P_SIGNUM(ALRM);
748 P_SIGNUM(TERM);
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300749 P_SIGNUM(CHLD);
750 P_SIGNUM(CONT);
751 P_SIGNUM(STOP);
752 P_SIGNUM(TSTP);
753 P_SIGNUM(TTIN);
754 P_SIGNUM(TTOU);
755 P_SIGNUM(URG);
756 P_SIGNUM(XCPU);
757 P_SIGNUM(XFSZ);
758 P_SIGNUM(VTALRM);
759 P_SIGNUM(PROF);
760 P_SIGNUM(WINCH);
761 P_SIGNUM(IO);
762 P_SIGNUM(PWR);
763 P_SIGNUM(SYS);
Ben Hutchings02c5bb42014-02-06 01:00:41 +0000764#ifdef SIGEMT
765 P_SIGNUM(EMT);
766#endif
767#ifdef SIGSTKFLT
768 P_SIGNUM(STKFLT);
769#endif
770#ifdef SIGSWI
771 P_SIGNUM(SWI);
772#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300773 default: break;
774 }
775
776 return scnprintf(bf, size, "%#x", sig);
777}
778
779#define SCA_SIGNUM syscall_arg__scnprintf_signum
780
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300781#if defined(__i386__) || defined(__x86_64__)
782/*
783 * FIXME: Make this available to all arches.
784 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300785#define TCGETS 0x5401
786
787static const char *tioctls[] = {
788 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
789 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
790 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
791 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
792 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
793 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
794 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
795 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
796 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
797 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
798 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
799 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
800 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
801 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
802 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
803};
804
805static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300806#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300807
Arnaldo Carvalho de Melo6fb35b92016-04-13 11:50:23 -0300808#ifndef SECCOMP_SET_MODE_STRICT
809#define SECCOMP_SET_MODE_STRICT 0
810#endif
811#ifndef SECCOMP_SET_MODE_FILTER
812#define SECCOMP_SET_MODE_FILTER 1
813#endif
814
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300815static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg)
816{
817 int op = arg->val;
818 size_t printed = 0;
819
820 switch (op) {
821#define P_SECCOMP_SET_MODE_OP(n) case SECCOMP_SET_MODE_##n: printed = scnprintf(bf, size, #n); break
822 P_SECCOMP_SET_MODE_OP(STRICT);
823 P_SECCOMP_SET_MODE_OP(FILTER);
824#undef P_SECCOMP_SET_MODE_OP
825 default: printed = scnprintf(bf, size, "%#x", op); break;
826 }
827
828 return printed;
829}
830
831#define SCA_SECCOMP_OP syscall_arg__scnprintf_seccomp_op
832
Arnaldo Carvalho de Melo6fb35b92016-04-13 11:50:23 -0300833#ifndef SECCOMP_FILTER_FLAG_TSYNC
834#define SECCOMP_FILTER_FLAG_TSYNC 1
835#endif
836
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300837static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size,
838 struct syscall_arg *arg)
839{
840 int printed = 0, flags = arg->val;
841
842#define P_FLAG(n) \
843 if (flags & SECCOMP_FILTER_FLAG_##n) { \
844 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
845 flags &= ~SECCOMP_FILTER_FLAG_##n; \
846 }
847
848 P_FLAG(TSYNC);
849#undef P_FLAG
850
851 if (flags)
852 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
853
854 return printed;
855}
856
857#define SCA_SECCOMP_FLAGS syscall_arg__scnprintf_seccomp_flags
858
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300859#ifndef GRND_NONBLOCK
860#define GRND_NONBLOCK 0x0001
861#endif
862#ifndef GRND_RANDOM
863#define GRND_RANDOM 0x0002
864#endif
865
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300866static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
867 struct syscall_arg *arg)
868{
869 int printed = 0, flags = arg->val;
870
871#define P_FLAG(n) \
872 if (flags & GRND_##n) { \
873 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
874 flags &= ~GRND_##n; \
875 }
876
877 P_FLAG(RANDOM);
878 P_FLAG(NONBLOCK);
879#undef P_FLAG
880
881 if (flags)
882 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
883
884 return printed;
885}
886
887#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
888
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300889#define STRARRAY(arg, name, array) \
890 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
891 .arg_parm = { [arg] = &strarray__##array, }
892
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300893#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300894#include "trace/beauty/pid.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300895#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300896#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300897#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300898#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300899#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300900
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300901static struct syscall_fmt {
902 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300903 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300904 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300905 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300906 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300907 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300908 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300909 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300910} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300911 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300912 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
913 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300914 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300915 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300916 { .name = "brk", .hexret = true,
917 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300918 { .name = "chdir", .errmsg = true,
919 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
920 { .name = "chmod", .errmsg = true,
921 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
922 { .name = "chroot", .errmsg = true,
923 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600924 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300925 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300926 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300927 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300928 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300929 { .name = "creat", .errmsg = true,
930 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300931 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300932 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300933 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300934 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300935 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300936 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300937 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300938 { .name = "eventfd2", .errmsg = true,
939 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300940 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300941 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
942 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300943 { .name = "fadvise64", .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 = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300946 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300947 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300948 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300949 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300950 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300951 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300952 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
953 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300954 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300955 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300956 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300957 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
958 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300959 { .name = "fcntl", .errmsg = true,
960 .arg_scnprintf = { [0] = SCA_FD, /* fd */
961 [1] = SCA_STRARRAY, /* cmd */ },
962 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
963 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300964 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300965 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300966 .arg_scnprintf = { [0] = SCA_FD, /* fd */
967 [1] = SCA_FLOCK, /* cmd */ }, },
968 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300969 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300970 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300971 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300972 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300973 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
974 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300975 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300976 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300977 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300978 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300979 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300980 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300981 { .name = "futex", .errmsg = true,
982 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300983 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300984 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
985 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300986 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300987 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300988 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300989 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300990 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300991 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300992 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300993 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300994 { .name = "getrandom", .errmsg = true,
995 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300996 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300997 { .name = "getxattr", .errmsg = true,
998 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
999 { .name = "inotify_add_watch", .errmsg = true,
1000 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001001 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001002 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001003#if defined(__i386__) || defined(__x86_64__)
1004/*
1005 * FIXME: Make this available to all arches.
1006 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001007 [1] = SCA_STRHEXARRAY, /* cmd */
1008 [2] = SCA_HEX, /* arg */ },
1009 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001010#else
1011 [2] = SCA_HEX, /* arg */ }, },
1012#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -03001013 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001014 { .name = "kill", .errmsg = true,
1015 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001016 { .name = "lchown", .errmsg = true,
1017 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1018 { .name = "lgetxattr", .errmsg = true,
1019 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001020 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001021 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001022 { .name = "listxattr", .errmsg = true,
1023 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001024 { .name = "llistxattr", .errmsg = true,
1025 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1026 { .name = "lremovexattr", .errmsg = true,
1027 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001028 { .name = "lseek", .errmsg = true,
1029 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1030 [2] = SCA_STRARRAY, /* whence */ },
1031 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001032 { .name = "lsetxattr", .errmsg = true,
1033 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001034 { .name = "lstat", .errmsg = true, .alias = "newlstat",
1035 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001036 { .name = "lsxattr", .errmsg = true,
1037 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001038 { .name = "madvise", .errmsg = true,
1039 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1040 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001041 { .name = "mkdir", .errmsg = true,
1042 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001043 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001044 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1045 [1] = SCA_FILENAME, /* pathname */ }, },
1046 { .name = "mknod", .errmsg = true,
1047 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001048 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001049 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1050 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001051 { .name = "mlock", .errmsg = true,
1052 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1053 { .name = "mlockall", .errmsg = true,
1054 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001055 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001056 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001057 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001058 [3] = SCA_MMAP_FLAGS, /* flags */
1059 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001060 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001061 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1062 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001063 { .name = "mq_unlink", .errmsg = true,
1064 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001065 { .name = "mremap", .hexret = true,
1066 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001067 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001068 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001069 { .name = "munlock", .errmsg = true,
1070 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001071 { .name = "munmap", .errmsg = true,
1072 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001073 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001074 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001075 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001076 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1077 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001078 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001079 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1080 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001081 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001082 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1083 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001084 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001085 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001086 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001087 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001088 { .name = "perf_event_open", .errmsg = true,
1089 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1090 [2] = SCA_INT, /* cpu */
1091 [3] = SCA_FD, /* group_fd */
1092 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001093 { .name = "pipe2", .errmsg = true,
1094 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001095 { .name = "poll", .errmsg = true, .timeout = true, },
1096 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001097 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001098 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001099 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001100 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001101 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001102 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001103 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001104 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001105 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001106 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001107 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001108 { .name = "readlink", .errmsg = true,
1109 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001110 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001111 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1112 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001113 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001114 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001115 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001116 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1117 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001118 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001119 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1120 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001121 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001122 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1123 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001124 { .name = "removexattr", .errmsg = true,
1125 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001126 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001127 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001128 { .name = "rmdir", .errmsg = true,
1129 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001130 { .name = "rt_sigaction", .errmsg = true,
1131 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001132 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001133 { .name = "rt_sigqueueinfo", .errmsg = true,
1134 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1135 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1136 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001137 { .name = "sched_setscheduler", .errmsg = true,
1138 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001139 { .name = "seccomp", .errmsg = true,
1140 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
1141 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001142 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001143 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001144 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1145 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001146 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001147 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1148 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001149 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001150 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1151 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001152 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001153 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001154 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001155 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001156 { .name = "setxattr", .errmsg = true,
1157 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001158 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001159 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001160 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001161 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1162 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001163 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001164 { .name = "socketpair", .errmsg = true,
1165 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1166 [1] = SCA_SK_TYPE, /* type */ },
1167 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001168 { .name = "stat", .errmsg = true, .alias = "newstat",
1169 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001170 { .name = "statfs", .errmsg = true,
1171 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1172 { .name = "swapoff", .errmsg = true,
1173 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1174 { .name = "swapon", .errmsg = true,
1175 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001176 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001177 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001178 { .name = "tgkill", .errmsg = true,
1179 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1180 { .name = "tkill", .errmsg = true,
1181 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001182 { .name = "truncate", .errmsg = true,
1183 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001184 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001185 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001186 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1187 [1] = SCA_FILENAME, /* pathname */ }, },
1188 { .name = "utime", .errmsg = true,
1189 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001190 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001191 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1192 [1] = SCA_FILENAME, /* filename */ }, },
1193 { .name = "utimes", .errmsg = true,
1194 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001195 { .name = "vmsplice", .errmsg = true,
1196 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001197 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001198 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001199 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001200 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001201 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001202 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001203 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001204 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001205};
1206
1207static int syscall_fmt__cmp(const void *name, const void *fmtp)
1208{
1209 const struct syscall_fmt *fmt = fmtp;
1210 return strcmp(name, fmt->name);
1211}
1212
1213static struct syscall_fmt *syscall_fmt__find(const char *name)
1214{
1215 const int nmemb = ARRAY_SIZE(syscall_fmts);
1216 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1217}
1218
1219struct syscall {
1220 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001221 int nr_args;
1222 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001223 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001224 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001225 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001226 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001227 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001228};
1229
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001230static size_t fprintf_duration(unsigned long t, FILE *fp)
1231{
1232 double duration = (double)t / NSEC_PER_MSEC;
1233 size_t printed = fprintf(fp, "(");
1234
1235 if (duration >= 1.0)
1236 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1237 else if (duration >= 0.01)
1238 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1239 else
1240 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001241 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001242}
1243
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001244/**
1245 * filename.ptr: The filename char pointer that will be vfs_getname'd
1246 * filename.entry_str_pos: Where to insert the string translated from
1247 * filename.ptr by the vfs_getname tracepoint/kprobe.
1248 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001249struct thread_trace {
1250 u64 entry_time;
1251 u64 exit_time;
1252 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001253 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001254 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001255 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001256 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001257 struct {
1258 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001259 short int entry_str_pos;
1260 bool pending_open;
1261 unsigned int namelen;
1262 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001263 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001264 struct {
1265 int max;
1266 char **table;
1267 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001268
1269 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001270};
1271
1272static struct thread_trace *thread_trace__new(void)
1273{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001274 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1275
1276 if (ttrace)
1277 ttrace->paths.max = -1;
1278
David Ahernbf2575c2013-10-08 21:26:53 -06001279 ttrace->syscall_stats = intlist__new(NULL);
1280
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001281 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001282}
1283
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001284static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001285{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001286 struct thread_trace *ttrace;
1287
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001288 if (thread == NULL)
1289 goto fail;
1290
Namhyung Kim89dceb22014-10-06 09:46:03 +09001291 if (thread__priv(thread) == NULL)
1292 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001293
Namhyung Kim89dceb22014-10-06 09:46:03 +09001294 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001295 goto fail;
1296
Namhyung Kim89dceb22014-10-06 09:46:03 +09001297 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001298 ++ttrace->nr_events;
1299
1300 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001301fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001302 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001303 "WARNING: not enough memory, dropping samples!\n");
1304 return NULL;
1305}
1306
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001307#define TRACE_PFMAJ (1 << 0)
1308#define TRACE_PFMIN (1 << 1)
1309
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001310static const size_t trace__entry_str_size = 2048;
1311
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001312static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001313{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001314 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001315
1316 if (fd > ttrace->paths.max) {
1317 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1318
1319 if (npath == NULL)
1320 return -1;
1321
1322 if (ttrace->paths.max != -1) {
1323 memset(npath + ttrace->paths.max + 1, 0,
1324 (fd - ttrace->paths.max) * sizeof(char *));
1325 } else {
1326 memset(npath, 0, (fd + 1) * sizeof(char *));
1327 }
1328
1329 ttrace->paths.table = npath;
1330 ttrace->paths.max = fd;
1331 }
1332
1333 ttrace->paths.table[fd] = strdup(pathname);
1334
1335 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1336}
1337
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001338static int thread__read_fd_path(struct thread *thread, int fd)
1339{
1340 char linkname[PATH_MAX], pathname[PATH_MAX];
1341 struct stat st;
1342 int ret;
1343
1344 if (thread->pid_ == thread->tid) {
1345 scnprintf(linkname, sizeof(linkname),
1346 "/proc/%d/fd/%d", thread->pid_, fd);
1347 } else {
1348 scnprintf(linkname, sizeof(linkname),
1349 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1350 }
1351
1352 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1353 return -1;
1354
1355 ret = readlink(linkname, pathname, sizeof(pathname));
1356
1357 if (ret < 0 || ret > st.st_size)
1358 return -1;
1359
1360 pathname[ret] = '\0';
1361 return trace__set_fd_pathname(thread, fd, pathname);
1362}
1363
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001364static const char *thread__fd_path(struct thread *thread, int fd,
1365 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001366{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001367 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001368
1369 if (ttrace == NULL)
1370 return NULL;
1371
1372 if (fd < 0)
1373 return NULL;
1374
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001375 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001376 if (!trace->live)
1377 return NULL;
1378 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001379 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001380 return NULL;
1381 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001382
1383 return ttrace->paths.table[fd];
1384}
1385
1386static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1387 struct syscall_arg *arg)
1388{
1389 int fd = arg->val;
1390 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001391 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001392
1393 if (path)
1394 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1395
1396 return printed;
1397}
1398
1399static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1400 struct syscall_arg *arg)
1401{
1402 int fd = arg->val;
1403 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001404 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001405
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001406 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1407 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001408
1409 return printed;
1410}
1411
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001412static void thread__set_filename_pos(struct thread *thread, const char *bf,
1413 unsigned long ptr)
1414{
1415 struct thread_trace *ttrace = thread__priv(thread);
1416
1417 ttrace->filename.ptr = ptr;
1418 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1419}
1420
1421static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1422 struct syscall_arg *arg)
1423{
1424 unsigned long ptr = arg->val;
1425
1426 if (!arg->trace->vfs_getname)
1427 return scnprintf(bf, size, "%#x", ptr);
1428
1429 thread__set_filename_pos(arg->thread, bf, ptr);
1430 return 0;
1431}
1432
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001433static bool trace__filter_duration(struct trace *trace, double t)
1434{
1435 return t < (trace->duration_filter * NSEC_PER_MSEC);
1436}
1437
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001438static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1439{
1440 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1441
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001442 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001443}
1444
Namhyung Kimf15eb532012-10-05 14:02:16 +09001445static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001446static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001447
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001448static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001449{
1450 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001451 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001452}
1453
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001454static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001455 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001456{
1457 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001458 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001459
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001460 if (trace->multiple_threads) {
1461 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001462 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001463 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001464 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001465
1466 return printed;
1467}
1468
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001469static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001470 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001471{
1472 int ret = 0;
1473
1474 switch (event->header.type) {
1475 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001476 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001477 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001478 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001479 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001480 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001481 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001482 break;
1483 }
1484
1485 return ret;
1486}
1487
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001488static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001489 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001490 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001491 struct machine *machine)
1492{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001493 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001494 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001495}
1496
1497static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1498{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001499 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001500
1501 if (err)
1502 return err;
1503
David Ahern8fb598e2013-09-28 13:13:00 -06001504 trace->host = machine__new_host();
1505 if (trace->host == NULL)
1506 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001507
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001508 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001509 return -errno;
1510
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001511 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001512 evlist->threads, trace__tool_process, false,
1513 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001514 if (err)
1515 symbol__exit();
1516
1517 return err;
1518}
1519
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001520static int syscall__set_arg_fmts(struct syscall *sc)
1521{
1522 struct format_field *field;
1523 int idx = 0;
1524
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001525 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001526 if (sc->arg_scnprintf == NULL)
1527 return -1;
1528
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001529 if (sc->fmt)
1530 sc->arg_parm = sc->fmt->arg_parm;
1531
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001532 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001533 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1534 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1535 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001536 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001537 else if (strcmp(field->type, "pid_t") == 0)
1538 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001539 else if (strcmp(field->type, "umode_t") == 0)
1540 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001541 ++idx;
1542 }
1543
1544 return 0;
1545}
1546
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001547static int trace__read_syscall_info(struct trace *trace, int id)
1548{
1549 char tp_name[128];
1550 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001551 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001552
1553 if (name == NULL)
1554 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001555
1556 if (id > trace->syscalls.max) {
1557 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1558
1559 if (nsyscalls == NULL)
1560 return -1;
1561
1562 if (trace->syscalls.max != -1) {
1563 memset(nsyscalls + trace->syscalls.max + 1, 0,
1564 (id - trace->syscalls.max) * sizeof(*sc));
1565 } else {
1566 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1567 }
1568
1569 trace->syscalls.table = nsyscalls;
1570 trace->syscalls.max = id;
1571 }
1572
1573 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001574 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001575
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001576 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001577
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001578 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001579 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001580
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001581 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001582 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001583 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001584 }
1585
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001586 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001587 return -1;
1588
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001589 sc->args = sc->tp_format->format.fields;
1590 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001591 /*
1592 * We need to check and discard the first variable '__syscall_nr'
1593 * or 'nr' that mean the syscall number. It is needless here.
1594 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1595 */
1596 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001597 sc->args = sc->args->next;
1598 --sc->nr_args;
1599 }
1600
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001601 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1602
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001603 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001604}
1605
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001606static int trace__validate_ev_qualifier(struct trace *trace)
1607{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001608 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001609 struct str_node *pos;
1610
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001611 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1612 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1613 sizeof(trace->ev_qualifier_ids.entries[0]));
1614
1615 if (trace->ev_qualifier_ids.entries == NULL) {
1616 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1617 trace->output);
1618 err = -EINVAL;
1619 goto out;
1620 }
1621
1622 i = 0;
1623
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001624 strlist__for_each(pos, trace->ev_qualifier) {
1625 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001626 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001627
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001628 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001629 if (err == 0) {
1630 fputs("Error:\tInvalid syscall ", trace->output);
1631 err = -EINVAL;
1632 } else {
1633 fputs(", ", trace->output);
1634 }
1635
1636 fputs(sc, trace->output);
1637 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001638
1639 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001640 }
1641
1642 if (err < 0) {
1643 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1644 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001645 zfree(&trace->ev_qualifier_ids.entries);
1646 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001647 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001648out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001649 return err;
1650}
1651
David Ahern55d43bc2015-02-19 15:00:22 -05001652/*
1653 * args is to be interpreted as a series of longs but we need to handle
1654 * 8-byte unaligned accesses. args points to raw_data within the event
1655 * and raw_data is guaranteed to be 8-byte unaligned because it is
1656 * preceded by raw_size which is a u32. So we need to copy args to a temp
1657 * variable to read it. Most notably this avoids extended load instructions
1658 * on unaligned addresses
1659 */
1660
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001661static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001662 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001663 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001664{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001665 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001666 unsigned char *p;
1667 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001668
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001669 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001670 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001671 u8 bit = 1;
1672 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001673 .idx = 0,
1674 .mask = 0,
1675 .trace = trace,
1676 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001677 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001678
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001679 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001680 field = field->next, ++arg.idx, bit <<= 1) {
1681 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001682 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001683
1684 /* special care for unaligned accesses */
1685 p = args + sizeof(unsigned long) * arg.idx;
1686 memcpy(&val, p, sizeof(val));
1687
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001688 /*
1689 * Suppress this argument if its value is zero and
1690 * and we don't have a string associated in an
1691 * strarray for it.
1692 */
David Ahern55d43bc2015-02-19 15:00:22 -05001693 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001694 !(sc->arg_scnprintf &&
1695 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1696 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001697 continue;
1698
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001699 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001700 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001701 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001702 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001703 if (sc->arg_parm)
1704 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001705 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1706 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001707 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001708 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001709 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001710 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001711 }
1712 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001713 int i = 0;
1714
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001715 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001716 /* special care for unaligned accesses */
1717 p = args + sizeof(unsigned long) * i;
1718 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001719 printed += scnprintf(bf + printed, size - printed,
1720 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001721 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001722 ++i;
1723 }
1724 }
1725
1726 return printed;
1727}
1728
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001729typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001730 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001731 struct perf_sample *sample);
1732
1733static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001734 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001735{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001736
1737 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001738
1739 /*
1740 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1741 * before that, leaving at a higher verbosity level till that is
1742 * explained. Reproduced with plain ftrace with:
1743 *
1744 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1745 * grep "NR -1 " /t/trace_pipe
1746 *
1747 * After generating some load on the machine.
1748 */
1749 if (verbose > 1) {
1750 static u64 n;
1751 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1752 id, perf_evsel__name(evsel), ++n);
1753 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001754 return NULL;
1755 }
1756
1757 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1758 trace__read_syscall_info(trace, id))
1759 goto out_cant_read;
1760
1761 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1762 goto out_cant_read;
1763
1764 return &trace->syscalls.table[id];
1765
1766out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001767 if (verbose) {
1768 fprintf(trace->output, "Problems reading syscall %d", id);
1769 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1770 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1771 fputs(" information\n", trace->output);
1772 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001773 return NULL;
1774}
1775
David Ahernbf2575c2013-10-08 21:26:53 -06001776static void thread__update_stats(struct thread_trace *ttrace,
1777 int id, struct perf_sample *sample)
1778{
1779 struct int_node *inode;
1780 struct stats *stats;
1781 u64 duration = 0;
1782
1783 inode = intlist__findnew(ttrace->syscall_stats, id);
1784 if (inode == NULL)
1785 return;
1786
1787 stats = inode->priv;
1788 if (stats == NULL) {
1789 stats = malloc(sizeof(struct stats));
1790 if (stats == NULL)
1791 return;
1792 init_stats(stats);
1793 inode->priv = stats;
1794 }
1795
1796 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1797 duration = sample->time - ttrace->entry_time;
1798
1799 update_stats(stats, duration);
1800}
1801
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001802static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1803{
1804 struct thread_trace *ttrace;
1805 u64 duration;
1806 size_t printed;
1807
1808 if (trace->current == NULL)
1809 return 0;
1810
1811 ttrace = thread__priv(trace->current);
1812
1813 if (!ttrace->entry_pending)
1814 return 0;
1815
1816 duration = sample->time - ttrace->entry_time;
1817
1818 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1819 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1820 ttrace->entry_pending = false;
1821
1822 return printed;
1823}
1824
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001825static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001826 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001827 struct perf_sample *sample)
1828{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001829 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001830 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001831 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001832 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001833 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001834 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001835 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001836
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001837 if (sc == NULL)
1838 return -1;
1839
David Ahern8fb598e2013-09-28 13:13:00 -06001840 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001841 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001842 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001843 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001844
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001845 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001846
1847 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001848 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001849 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001850 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001851 }
1852
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001853 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001854 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001855
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001856 ttrace->entry_time = sample->time;
1857 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001858 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001859
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001860 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001861 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001862
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001863 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001864 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001865 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1866 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001867 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001868 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001869 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001870 /* See trace__vfs_getname & trace__sys_exit */
1871 ttrace->filename.pending_open = false;
1872 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001873
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001874 if (trace->current != thread) {
1875 thread__put(trace->current);
1876 trace->current = thread__get(thread);
1877 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001878 err = 0;
1879out_put:
1880 thread__put(thread);
1881 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001882}
1883
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001884static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1885 struct perf_sample *sample,
1886 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001887{
1888 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001889
1890 if (machine__resolve(trace->host, &al, sample) < 0 ||
1891 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1892 return -1;
1893
1894 return 0;
1895}
1896
1897static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1898{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001899 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001900 const unsigned int print_opts = EVSEL__PRINT_SYM |
1901 EVSEL__PRINT_DSO |
1902 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001903
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001904 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001905}
1906
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001907static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001908 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001909 struct perf_sample *sample)
1910{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001911 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001912 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001913 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001914 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001915 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001916 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001917
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001918 if (sc == NULL)
1919 return -1;
1920
David Ahern8fb598e2013-09-28 13:13:00 -06001921 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001922 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001923 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001924 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001925
David Ahernbf2575c2013-10-08 21:26:53 -06001926 if (trace->summary)
1927 thread__update_stats(ttrace, id, sample);
1928
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001929 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001930
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001931 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001932 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1933 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001934 ++trace->stats.vfs_getname;
1935 }
1936
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001937 ttrace->exit_time = sample->time;
1938
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001939 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001940 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001941 if (trace__filter_duration(trace, duration))
1942 goto out;
1943 } else if (trace->duration_filter)
1944 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001945
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001946 if (sample->callchain) {
1947 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1948 if (callchain_ret == 0) {
1949 if (callchain_cursor.nr < trace->min_stack)
1950 goto out;
1951 callchain_ret = 1;
1952 }
1953 }
1954
David Ahernfd2eaba2013-11-12 09:31:15 -07001955 if (trace->summary_only)
1956 goto out;
1957
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001958 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001959
1960 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001961 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001962 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001963 fprintf(trace->output, " ... [");
1964 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1965 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001966 }
1967
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001968 if (sc->fmt == NULL) {
1969signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001970 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001971 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001972 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001973 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1974 *e = audit_errno_to_name(-ret);
1975
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001976 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001977 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001978 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001979 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001980 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001981 else if (sc->fmt->errpid) {
1982 struct thread *child = machine__find_thread(trace->host, ret, ret);
1983
1984 if (child != NULL) {
1985 fprintf(trace->output, ") = %ld", ret);
1986 if (child->comm_set)
1987 fprintf(trace->output, " (%s)", thread__comm_str(child));
1988 thread__put(child);
1989 }
1990 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001991 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001992
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001993 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001994
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001995 if (callchain_ret > 0)
1996 trace__fprintf_callchain(trace, sample);
1997 else if (callchain_ret < 0)
1998 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001999out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002000 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002001 err = 0;
2002out_put:
2003 thread__put(thread);
2004 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002005}
2006
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002007static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002008 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002009 struct perf_sample *sample)
2010{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002011 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2012 struct thread_trace *ttrace;
2013 size_t filename_len, entry_str_len, to_move;
2014 ssize_t remaining_space;
2015 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002016 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002017
2018 if (!thread)
2019 goto out;
2020
2021 ttrace = thread__priv(thread);
2022 if (!ttrace)
2023 goto out;
2024
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002025 filename_len = strlen(filename);
2026
2027 if (ttrace->filename.namelen < filename_len) {
2028 char *f = realloc(ttrace->filename.name, filename_len + 1);
2029
2030 if (f == NULL)
2031 goto out;
2032
2033 ttrace->filename.namelen = filename_len;
2034 ttrace->filename.name = f;
2035 }
2036
2037 strcpy(ttrace->filename.name, filename);
2038 ttrace->filename.pending_open = true;
2039
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002040 if (!ttrace->filename.ptr)
2041 goto out;
2042
2043 entry_str_len = strlen(ttrace->entry_str);
2044 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2045 if (remaining_space <= 0)
2046 goto out;
2047
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002048 if (filename_len > (size_t)remaining_space) {
2049 filename += filename_len - remaining_space;
2050 filename_len = remaining_space;
2051 }
2052
2053 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2054 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2055 memmove(pos + filename_len, pos, to_move);
2056 memcpy(pos, filename, filename_len);
2057
2058 ttrace->filename.ptr = 0;
2059 ttrace->filename.entry_str_pos = 0;
2060out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002061 return 0;
2062}
2063
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002064static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002065 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002066 struct perf_sample *sample)
2067{
2068 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2069 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06002070 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03002071 sample->pid,
2072 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002073 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002074
2075 if (ttrace == NULL)
2076 goto out_dump;
2077
2078 ttrace->runtime_ms += runtime_ms;
2079 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002080 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002081 return 0;
2082
2083out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002084 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002085 evsel->name,
2086 perf_evsel__strval(evsel, sample, "comm"),
2087 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2088 runtime,
2089 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002090 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002091 return 0;
2092}
2093
Wang Nan1d6c9402016-02-26 09:31:55 +00002094static void bpf_output__printer(enum binary_printer_ops op,
2095 unsigned int val, void *extra)
2096{
2097 FILE *output = extra;
2098 unsigned char ch = (unsigned char)val;
2099
2100 switch (op) {
2101 case BINARY_PRINT_CHAR_DATA:
2102 fprintf(output, "%c", isprint(ch) ? ch : '.');
2103 break;
2104 case BINARY_PRINT_DATA_BEGIN:
2105 case BINARY_PRINT_LINE_BEGIN:
2106 case BINARY_PRINT_ADDR:
2107 case BINARY_PRINT_NUM_DATA:
2108 case BINARY_PRINT_NUM_PAD:
2109 case BINARY_PRINT_SEP:
2110 case BINARY_PRINT_CHAR_PAD:
2111 case BINARY_PRINT_LINE_END:
2112 case BINARY_PRINT_DATA_END:
2113 default:
2114 break;
2115 }
2116}
2117
2118static void bpf_output__fprintf(struct trace *trace,
2119 struct perf_sample *sample)
2120{
2121 print_binary(sample->raw_data, sample->raw_size, 8,
2122 bpf_output__printer, trace->output);
2123}
2124
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002125static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2126 union perf_event *event __maybe_unused,
2127 struct perf_sample *sample)
2128{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002129 int callchain_ret = 0;
2130
2131 if (sample->callchain) {
2132 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2133 if (callchain_ret == 0) {
2134 if (callchain_cursor.nr < trace->min_stack)
2135 goto out;
2136 callchain_ret = 1;
2137 }
2138 }
2139
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002140 trace__printf_interrupted_entry(trace, sample);
2141 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002142
2143 if (trace->trace_syscalls)
2144 fprintf(trace->output, "( ): ");
2145
2146 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002147
Wang Nan1d6c9402016-02-26 09:31:55 +00002148 if (perf_evsel__is_bpf_output(evsel)) {
2149 bpf_output__fprintf(trace, sample);
2150 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002151 event_format__fprintf(evsel->tp_format, sample->cpu,
2152 sample->raw_data, sample->raw_size,
2153 trace->output);
2154 }
2155
2156 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03002157
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002158 if (callchain_ret > 0)
2159 trace__fprintf_callchain(trace, sample);
2160 else if (callchain_ret < 0)
2161 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
2162out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002163 return 0;
2164}
2165
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002166static void print_location(FILE *f, struct perf_sample *sample,
2167 struct addr_location *al,
2168 bool print_dso, bool print_sym)
2169{
2170
2171 if ((verbose || print_dso) && al->map)
2172 fprintf(f, "%s@", al->map->dso->long_name);
2173
2174 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002175 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002176 al->addr - al->sym->start);
2177 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002178 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002179 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002180 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002181}
2182
2183static int trace__pgfault(struct trace *trace,
2184 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002185 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002186 struct perf_sample *sample)
2187{
2188 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002189 struct addr_location al;
2190 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002191 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002192 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002193
2194 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002195 ttrace = thread__trace(thread, trace->output);
2196 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002197 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002198
2199 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2200 ttrace->pfmaj++;
2201 else
2202 ttrace->pfmin++;
2203
2204 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002205 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002206
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002207 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002208 sample->ip, &al);
2209
2210 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2211
2212 fprintf(trace->output, "%sfault [",
2213 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2214 "maj" : "min");
2215
2216 print_location(trace->output, sample, &al, false, true);
2217
2218 fprintf(trace->output, "] => ");
2219
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002220 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002221 sample->addr, &al);
2222
2223 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002224 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002225 MAP__FUNCTION, sample->addr, &al);
2226
2227 if (al.map)
2228 map_type = 'x';
2229 else
2230 map_type = '?';
2231 }
2232
2233 print_location(trace->output, sample, &al, true, false);
2234
2235 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002236
2237 if (sample->callchain) {
2238 if (trace__resolve_callchain(trace, evsel, sample, &callchain_cursor) == 0)
2239 trace__fprintf_callchain(trace, sample);
2240 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002241out:
2242 err = 0;
2243out_put:
2244 thread__put(thread);
2245 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002246}
2247
David Ahernbdc89662013-08-28 22:29:53 -06002248static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2249{
2250 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2251 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2252 return false;
2253
2254 if (trace->pid_list || trace->tid_list)
2255 return true;
2256
2257 return false;
2258}
2259
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002260static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002261 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002262 struct perf_sample *sample)
2263{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002264 /*
2265 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2266 * and don't use sample->time unconditionally, we may end up having
2267 * some other event in the future without PERF_SAMPLE_TIME for good
2268 * reason, i.e. we may not be interested in its timestamps, just in
2269 * it taking place, picking some piece of information when it
2270 * appears in our event stream (vfs_getname comes to mind).
2271 */
2272 if (trace->base_time == 0 && !trace->full_time &&
2273 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002274 trace->base_time = sample->time;
2275}
2276
David Ahern6810fc92013-08-28 22:29:52 -06002277static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002278 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002279 struct perf_sample *sample,
2280 struct perf_evsel *evsel,
2281 struct machine *machine __maybe_unused)
2282{
2283 struct trace *trace = container_of(tool, struct trace, tool);
2284 int err = 0;
2285
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002286 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002287
David Ahernbdc89662013-08-28 22:29:53 -06002288 if (skip_sample(trace, sample))
2289 return 0;
2290
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002291 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002292
David Ahern31605652013-12-04 19:41:41 -07002293 if (handler) {
2294 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002295 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002296 }
David Ahern6810fc92013-08-28 22:29:52 -06002297
2298 return err;
2299}
2300
David Ahernbdc89662013-08-28 22:29:53 -06002301static int parse_target_str(struct trace *trace)
2302{
2303 if (trace->opts.target.pid) {
2304 trace->pid_list = intlist__new(trace->opts.target.pid);
2305 if (trace->pid_list == NULL) {
2306 pr_err("Error parsing process id string\n");
2307 return -EINVAL;
2308 }
2309 }
2310
2311 if (trace->opts.target.tid) {
2312 trace->tid_list = intlist__new(trace->opts.target.tid);
2313 if (trace->tid_list == NULL) {
2314 pr_err("Error parsing thread id string\n");
2315 return -EINVAL;
2316 }
2317 }
2318
2319 return 0;
2320}
2321
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002322static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002323{
2324 unsigned int rec_argc, i, j;
2325 const char **rec_argv;
2326 const char * const record_args[] = {
2327 "record",
2328 "-R",
2329 "-m", "1024",
2330 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002331 };
2332
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002333 const char * const sc_args[] = { "-e", };
2334 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2335 const char * const majpf_args[] = { "-e", "major-faults" };
2336 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2337 const char * const minpf_args[] = { "-e", "minor-faults" };
2338 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2339
David Ahern9aca7f12013-12-04 19:41:39 -07002340 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002341 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2342 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002343 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2344
2345 if (rec_argv == NULL)
2346 return -ENOMEM;
2347
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002348 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002349 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002350 rec_argv[j++] = record_args[i];
2351
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002352 if (trace->trace_syscalls) {
2353 for (i = 0; i < sc_args_nr; i++)
2354 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002355
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002356 /* event string may be different for older kernels - e.g., RHEL6 */
2357 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2358 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2359 else if (is_valid_tracepoint("syscalls:sys_enter"))
2360 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2361 else {
2362 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2363 return -1;
2364 }
David Ahern9aca7f12013-12-04 19:41:39 -07002365 }
David Ahern9aca7f12013-12-04 19:41:39 -07002366
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002367 if (trace->trace_pgfaults & TRACE_PFMAJ)
2368 for (i = 0; i < majpf_args_nr; i++)
2369 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002370
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002371 if (trace->trace_pgfaults & TRACE_PFMIN)
2372 for (i = 0; i < minpf_args_nr; i++)
2373 rec_argv[j++] = minpf_args[i];
2374
2375 for (i = 0; i < (unsigned int)argc; i++)
2376 rec_argv[j++] = argv[i];
2377
2378 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002379}
2380
David Ahernbf2575c2013-10-08 21:26:53 -06002381static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2382
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002383static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002384{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002385 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002386
2387 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002388 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002389
2390 if (perf_evsel__field(evsel, "pathname") == NULL) {
2391 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002392 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002393 }
2394
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002395 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002396 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002397 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002398}
2399
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002400static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002401{
2402 struct perf_evsel *evsel;
2403 struct perf_event_attr attr = {
2404 .type = PERF_TYPE_SOFTWARE,
2405 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002406 };
2407
2408 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002409 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002410
2411 event_attr_init(&attr);
2412
2413 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002414 if (evsel)
2415 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002416
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002417 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002418}
2419
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002420static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2421{
2422 const u32 type = event->header.type;
2423 struct perf_evsel *evsel;
2424
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002425 if (type != PERF_RECORD_SAMPLE) {
2426 trace__process_event(trace, trace->host, event, sample);
2427 return;
2428 }
2429
2430 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2431 if (evsel == NULL) {
2432 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2433 return;
2434 }
2435
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002436 trace__set_base_time(trace, evsel, sample);
2437
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002438 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2439 sample->raw_data == NULL) {
2440 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2441 perf_evsel__name(evsel), sample->tid,
2442 sample->cpu, sample->raw_size);
2443 } else {
2444 tracepoint_handler handler = evsel->handler;
2445 handler(trace, evsel, event, sample);
2446 }
2447}
2448
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002449static int trace__add_syscall_newtp(struct trace *trace)
2450{
2451 int ret = -1;
2452 struct perf_evlist *evlist = trace->evlist;
2453 struct perf_evsel *sys_enter, *sys_exit;
2454
2455 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2456 if (sys_enter == NULL)
2457 goto out;
2458
2459 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2460 goto out_delete_sys_enter;
2461
2462 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2463 if (sys_exit == NULL)
2464 goto out_delete_sys_enter;
2465
2466 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2467 goto out_delete_sys_exit;
2468
2469 perf_evlist__add(evlist, sys_enter);
2470 perf_evlist__add(evlist, sys_exit);
2471
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002472 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002473 /*
2474 * We're interested only in the user space callchain
2475 * leading to the syscall, allow overriding that for
2476 * debugging reasons using --kernel_syscall_callchains
2477 */
2478 sys_exit->attr.exclude_callchain_kernel = 1;
2479 }
2480
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002481 trace->syscalls.events.sys_enter = sys_enter;
2482 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002483
2484 ret = 0;
2485out:
2486 return ret;
2487
2488out_delete_sys_exit:
2489 perf_evsel__delete_priv(sys_exit);
2490out_delete_sys_enter:
2491 perf_evsel__delete_priv(sys_enter);
2492 goto out;
2493}
2494
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002495static int trace__set_ev_qualifier_filter(struct trace *trace)
2496{
2497 int err = -1;
2498 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2499 trace->ev_qualifier_ids.nr,
2500 trace->ev_qualifier_ids.entries);
2501
2502 if (filter == NULL)
2503 goto out_enomem;
2504
2505 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2506 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2507
2508 free(filter);
2509out:
2510 return err;
2511out_enomem:
2512 errno = ENOMEM;
2513 goto out;
2514}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002515
Namhyung Kimf15eb532012-10-05 14:02:16 +09002516static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002517{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002518 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002519 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002520 int err = -1, i;
2521 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002522 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002523 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002524
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002525 trace->live = true;
2526
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002527 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002528 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002529
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002530 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002531 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002532
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002533 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2534 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2535 if (pgfault_maj == NULL)
2536 goto out_error_mem;
2537 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002538 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002539
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002540 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2541 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2542 if (pgfault_min == NULL)
2543 goto out_error_mem;
2544 perf_evlist__add(evlist, pgfault_min);
2545 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002546
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002547 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002548 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2549 trace__sched_stat_runtime))
2550 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002551
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002552 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2553 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002554 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002555 goto out_delete_evlist;
2556 }
2557
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002558 err = trace__symbols_init(trace, evlist);
2559 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002560 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002561 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002562 }
2563
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002564 perf_evlist__config(evlist, &trace->opts, NULL);
2565
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002566 if (callchain_param.enabled) {
2567 bool use_identifier = false;
2568
2569 if (trace->syscalls.events.sys_exit) {
2570 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2571 &trace->opts, &callchain_param);
2572 use_identifier = true;
2573 }
2574
2575 if (pgfault_maj) {
2576 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2577 use_identifier = true;
2578 }
2579
2580 if (pgfault_min) {
2581 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2582 use_identifier = true;
2583 }
2584
2585 if (use_identifier) {
2586 /*
2587 * Now we have evsels with different sample_ids, use
2588 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2589 * from a fixed position in each ring buffer record.
2590 *
2591 * As of this the changeset introducing this comment, this
2592 * isn't strictly needed, as the fields that can come before
2593 * PERF_SAMPLE_ID are all used, but we'll probably disable
2594 * some of those for things like copying the payload of
2595 * pointer syscall arguments, and for vfs_getname we don't
2596 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2597 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2598 */
2599 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2600 perf_evlist__reset_sample_bit(evlist, ID);
2601 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002602 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002603
Namhyung Kimf15eb532012-10-05 14:02:16 +09002604 signal(SIGCHLD, sig_handler);
2605 signal(SIGINT, sig_handler);
2606
2607 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002608 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002609 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002610 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002611 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002612 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002613 }
2614 }
2615
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002616 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002617 if (err < 0)
2618 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002619
Wang Nanba504232016-02-26 09:31:54 +00002620 err = bpf__apply_obj_config();
2621 if (err) {
2622 char errbuf[BUFSIZ];
2623
2624 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2625 pr_err("ERROR: Apply config to BPF failed: %s\n",
2626 errbuf);
2627 goto out_error_open;
2628 }
2629
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002630 /*
2631 * Better not use !target__has_task() here because we need to cover the
2632 * case where no threads were specified in the command line, but a
2633 * workload was, and in that case we will fill in the thread_map when
2634 * we fork the workload in perf_evlist__prepare_workload.
2635 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002636 if (trace->filter_pids.nr > 0)
2637 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002638 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002639 err = perf_evlist__set_filter_pid(evlist, getpid());
2640
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002641 if (err < 0)
2642 goto out_error_mem;
2643
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002644 if (trace->ev_qualifier_ids.nr > 0) {
2645 err = trace__set_ev_qualifier_filter(trace);
2646 if (err < 0)
2647 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002648
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002649 pr_debug("event qualifier tracepoint filter: %s\n",
2650 trace->syscalls.events.sys_exit->filter);
2651 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002652
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002653 err = perf_evlist__apply_filters(evlist, &evsel);
2654 if (err < 0)
2655 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002656
Jiri Olsaf8850372013-11-28 17:57:22 +01002657 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002658 if (err < 0)
2659 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002660
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002661 if (!target__none(&trace->opts.target))
2662 perf_evlist__enable(evlist);
2663
Namhyung Kimf15eb532012-10-05 14:02:16 +09002664 if (forks)
2665 perf_evlist__start_workload(evlist);
2666
Jiri Olsae13798c2015-06-23 00:36:02 +02002667 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002668 evlist->threads->nr > 1 ||
2669 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002670again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002671 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002672
2673 for (i = 0; i < evlist->nr_mmaps; i++) {
2674 union perf_event *event;
2675
2676 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002677 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002678
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002679 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002680
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002681 err = perf_evlist__parse_sample(evlist, event, &sample);
2682 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002683 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002684 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002685 }
2686
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002687 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002688next_event:
2689 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002690
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002691 if (interrupted)
2692 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002693
2694 if (done && !draining) {
2695 perf_evlist__disable(evlist);
2696 draining = true;
2697 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002698 }
2699 }
2700
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002701 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002702 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002703
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002704 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2705 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2706 draining = true;
2707
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002708 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002709 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002710 } else {
2711 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002712 }
2713
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002714out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002715 thread__zput(trace->current);
2716
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002717 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002718
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002719 if (!err) {
2720 if (trace->summary)
2721 trace__fprintf_thread_summary(trace, trace->output);
2722
2723 if (trace->show_tool_stats) {
2724 fprintf(trace->output, "Stats:\n "
2725 " vfs_getname : %" PRIu64 "\n"
2726 " proc_getname: %" PRIu64 "\n",
2727 trace->stats.vfs_getname,
2728 trace->stats.proc_getname);
2729 }
2730 }
David Ahernbf2575c2013-10-08 21:26:53 -06002731
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002732out_delete_evlist:
2733 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002734 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002735 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002736 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002737{
2738 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002739
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002740out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002741 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002742 goto out_error;
2743
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002744out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002745 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002746 goto out_error;
2747
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002748out_error_mmap:
2749 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2750 goto out_error;
2751
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002752out_error_open:
2753 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2754
2755out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002756 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302757 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002758
2759out_error_apply_filters:
2760 fprintf(trace->output,
2761 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2762 evsel->filter, perf_evsel__name(evsel), errno,
2763 strerror_r(errno, errbuf, sizeof(errbuf)));
2764 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002765}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002766out_error_mem:
2767 fprintf(trace->output, "Not enough memory to run!\n");
2768 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002769
2770out_errno:
2771 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2772 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002773}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002774
David Ahern6810fc92013-08-28 22:29:52 -06002775static int trace__replay(struct trace *trace)
2776{
2777 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002778 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002779 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002780 struct perf_data_file file = {
2781 .path = input_name,
2782 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002783 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002784 };
David Ahern6810fc92013-08-28 22:29:52 -06002785 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002786 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002787 int err = -1;
2788
2789 trace->tool.sample = trace__process_sample;
2790 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002791 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002792 trace->tool.comm = perf_event__process_comm;
2793 trace->tool.exit = perf_event__process_exit;
2794 trace->tool.fork = perf_event__process_fork;
2795 trace->tool.attr = perf_event__process_attr;
2796 trace->tool.tracing_data = perf_event__process_tracing_data;
2797 trace->tool.build_id = perf_event__process_build_id;
2798
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002799 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002800 trace->tool.ordering_requires_timestamps = true;
2801
2802 /* add tid to output */
2803 trace->multiple_threads = true;
2804
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002805 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002806 if (session == NULL)
Taeung Song52e02832014-09-24 10:33:37 +09002807 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002808
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002809 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002810 goto out;
2811
David Ahern8fb598e2013-09-28 13:13:00 -06002812 trace->host = &session->machines.host;
2813
David Ahern6810fc92013-08-28 22:29:52 -06002814 err = perf_session__set_tracepoints_handlers(session, handlers);
2815 if (err)
2816 goto out;
2817
Namhyung Kim003824e2013-11-12 15:25:00 +09002818 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2819 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002820 /* older kernels have syscalls tp versus raw_syscalls */
2821 if (evsel == NULL)
2822 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2823 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002824
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002825 if (evsel &&
2826 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2827 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002828 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2829 goto out;
2830 }
2831
2832 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2833 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002834 if (evsel == NULL)
2835 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2836 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002837 if (evsel &&
2838 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2839 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002840 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002841 goto out;
2842 }
2843
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002844 evlist__for_each(session->evlist, evsel) {
2845 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2846 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2847 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2848 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2849 evsel->handler = trace__pgfault;
2850 }
2851
David Ahernbdc89662013-08-28 22:29:53 -06002852 err = parse_target_str(trace);
2853 if (err != 0)
2854 goto out;
2855
David Ahern6810fc92013-08-28 22:29:52 -06002856 setup_pager();
2857
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002858 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002859 if (err)
2860 pr_err("Failed to process events, error %d", err);
2861
David Ahernbf2575c2013-10-08 21:26:53 -06002862 else if (trace->summary)
2863 trace__fprintf_thread_summary(trace, trace->output);
2864
David Ahern6810fc92013-08-28 22:29:52 -06002865out:
2866 perf_session__delete(session);
2867
2868 return err;
2869}
2870
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002871static size_t trace__fprintf_threads_header(FILE *fp)
2872{
2873 size_t printed;
2874
Pekka Enberg99ff7152013-11-12 16:42:14 +02002875 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002876
2877 return printed;
2878}
2879
2880static size_t thread__dump_stats(struct thread_trace *ttrace,
2881 struct trace *trace, FILE *fp)
2882{
2883 struct stats *stats;
2884 size_t printed = 0;
2885 struct syscall *sc;
2886 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2887
2888 if (inode == NULL)
2889 return 0;
2890
2891 printed += fprintf(fp, "\n");
2892
Milian Wolff834fd462015-08-06 11:24:29 +02002893 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2894 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2895 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002896
David Ahernbf2575c2013-10-08 21:26:53 -06002897 /* each int_node is a syscall */
2898 while (inode) {
2899 stats = inode->priv;
2900 if (stats) {
2901 double min = (double)(stats->min) / NSEC_PER_MSEC;
2902 double max = (double)(stats->max) / NSEC_PER_MSEC;
2903 double avg = avg_stats(stats);
2904 double pct;
2905 u64 n = (u64) stats->n;
2906
2907 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2908 avg /= NSEC_PER_MSEC;
2909
2910 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002911 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002912 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
2913 n, avg * n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002914 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002915 }
2916
2917 inode = intlist__next(inode);
2918 }
2919
2920 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002921
2922 return printed;
2923}
2924
David Ahern896cbb52013-09-28 13:12:59 -06002925/* struct used to pass data to per-thread function */
2926struct summary_data {
2927 FILE *fp;
2928 struct trace *trace;
2929 size_t printed;
2930};
2931
2932static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2933{
2934 struct summary_data *data = priv;
2935 FILE *fp = data->fp;
2936 size_t printed = data->printed;
2937 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002938 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002939 double ratio;
2940
2941 if (ttrace == NULL)
2942 return 0;
2943
2944 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2945
Pekka Enberg15e65c62013-11-14 18:43:30 +02002946 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002947 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002948 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002949 if (ttrace->pfmaj)
2950 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2951 if (ttrace->pfmin)
2952 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002953 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002954 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002955
2956 data->printed += printed;
2957
2958 return 0;
2959}
2960
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002961static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2962{
David Ahern896cbb52013-09-28 13:12:59 -06002963 struct summary_data data = {
2964 .fp = fp,
2965 .trace = trace
2966 };
2967 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002968
David Ahern896cbb52013-09-28 13:12:59 -06002969 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002970
David Ahern896cbb52013-09-28 13:12:59 -06002971 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002972}
2973
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002974static int trace__set_duration(const struct option *opt, const char *str,
2975 int unset __maybe_unused)
2976{
2977 struct trace *trace = opt->value;
2978
2979 trace->duration_filter = atof(str);
2980 return 0;
2981}
2982
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002983static int trace__set_filter_pids(const struct option *opt, const char *str,
2984 int unset __maybe_unused)
2985{
2986 int ret = -1;
2987 size_t i;
2988 struct trace *trace = opt->value;
2989 /*
2990 * FIXME: introduce a intarray class, plain parse csv and create a
2991 * { int nr, int entries[] } struct...
2992 */
2993 struct intlist *list = intlist__new(str);
2994
2995 if (list == NULL)
2996 return -1;
2997
2998 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2999 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
3000
3001 if (trace->filter_pids.entries == NULL)
3002 goto out;
3003
3004 trace->filter_pids.entries[0] = getpid();
3005
3006 for (i = 1; i < trace->filter_pids.nr; ++i)
3007 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
3008
3009 intlist__delete(list);
3010 ret = 0;
3011out:
3012 return ret;
3013}
3014
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003015static int trace__open_output(struct trace *trace, const char *filename)
3016{
3017 struct stat st;
3018
3019 if (!stat(filename, &st) && st.st_size) {
3020 char oldname[PATH_MAX];
3021
3022 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
3023 unlink(oldname);
3024 rename(filename, oldname);
3025 }
3026
3027 trace->output = fopen(filename, "w");
3028
3029 return trace->output == NULL ? -errno : 0;
3030}
3031
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003032static int parse_pagefaults(const struct option *opt, const char *str,
3033 int unset __maybe_unused)
3034{
3035 int *trace_pgfaults = opt->value;
3036
3037 if (strcmp(str, "all") == 0)
3038 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
3039 else if (strcmp(str, "maj") == 0)
3040 *trace_pgfaults |= TRACE_PFMAJ;
3041 else if (strcmp(str, "min") == 0)
3042 *trace_pgfaults |= TRACE_PFMIN;
3043 else
3044 return -1;
3045
3046 return 0;
3047}
3048
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003049static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3050{
3051 struct perf_evsel *evsel;
3052
3053 evlist__for_each(evlist, evsel)
3054 evsel->handler = handler;
3055}
3056
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003057int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3058{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003059 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003060 "perf trace [<options>] [<command>]",
3061 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003062 "perf trace record [<options>] [<command>]",
3063 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003064 NULL
3065 };
3066 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003067 .syscalls = {
3068 . max = -1,
3069 },
3070 .opts = {
3071 .target = {
3072 .uid = UINT_MAX,
3073 .uses_mmap = true,
3074 },
3075 .user_freq = UINT_MAX,
3076 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003077 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003078 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003079 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003080 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003081 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003082 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003083 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003084 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003085 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003086 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003087 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003088 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003089 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003090 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3091 "event selector. use 'perf list' to list available events",
3092 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003093 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3094 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003095 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03003096 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003097 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003098 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003099 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3100 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003101 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003102 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003103 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3104 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003105 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003106 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003107 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003108 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003109 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003110 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003111 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3112 "number of mmap data pages",
3113 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003114 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003115 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003116 OPT_CALLBACK(0, "duration", &trace, "float",
3117 "show only events with duration > N.M ms",
3118 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003119 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003120 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003121 OPT_BOOLEAN('T', "time", &trace.full_time,
3122 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003123 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3124 "Show only syscall summary with statistics"),
3125 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3126 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003127 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3128 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003129 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003130 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003131 OPT_CALLBACK(0, "call-graph", &trace.opts,
3132 "record_mode[,record_size]", record_callchain_help,
3133 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003134 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3135 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03003136 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3137 "Set the minimum stack depth when parsing the callchain, "
3138 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03003139 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3140 "Set the maximum stack depth when parsing the callchain, "
3141 "anything beyond the specified depth will be ignored. "
3142 "Default: " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04003143 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3144 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003145 OPT_END()
3146 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003147 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003148 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003149 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003150 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003151 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003152
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003153 signal(SIGSEGV, sighandler_dump_stack);
3154 signal(SIGFPE, sighandler_dump_stack);
3155
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003156 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003157 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003158
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003159 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003160 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003161 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003162 goto out;
3163 }
3164
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003165 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3166 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003167
Wang Nand7888572016-04-08 15:07:24 +00003168 err = bpf__setup_stdout(trace.evlist);
3169 if (err) {
3170 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3171 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3172 goto out;
3173 }
3174
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003175 err = -1;
3176
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003177 if (trace.trace_pgfaults) {
3178 trace.opts.sample_address = true;
3179 trace.opts.sample_time = true;
3180 }
3181
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003182 if (trace.opts.mmap_pages == UINT_MAX)
3183 mmap_pages_user_set = false;
3184
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003185 if (trace.max_stack == UINT_MAX) {
3186 trace.max_stack = PERF_MAX_STACK_DEPTH;
3187 max_stack_user_set = false;
3188 }
3189
3190#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003191 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003192 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
3193#endif
3194
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003195 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003196 if (!mmap_pages_user_set && geteuid() == 0)
3197 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3198
Milian Wolff566a0882016-04-08 13:34:15 +02003199 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003200 }
Milian Wolff566a0882016-04-08 13:34:15 +02003201
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003202 if (trace.evlist->nr_entries > 0)
3203 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3204
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003205 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3206 return trace__record(&trace, argc-1, &argv[1]);
3207
3208 /* summary_only implies summary option, but don't overwrite summary if set */
3209 if (trace.summary_only)
3210 trace.summary = trace.summary_only;
3211
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003212 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3213 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003214 pr_err("Please specify something to trace.\n");
3215 return -1;
3216 }
3217
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003218 if (!trace.trace_syscalls && ev_qualifier_str) {
3219 pr_err("The -e option can't be used with --no-syscalls.\n");
3220 goto out;
3221 }
3222
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003223 if (output_name != NULL) {
3224 err = trace__open_output(&trace, output_name);
3225 if (err < 0) {
3226 perror("failed to create output file");
3227 goto out;
3228 }
3229 }
3230
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003231 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3232
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003233 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003234 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003235 struct strlist_config slist_config = {
3236 .dirname = system_path(STRACE_GROUPS_DIR),
3237 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003238
3239 trace.not_ev_qualifier = *s == '!';
3240 if (trace.not_ev_qualifier)
3241 ++s;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003242 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003243 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003244 fputs("Not enough memory to parse event qualifier",
3245 trace.output);
3246 err = -ENOMEM;
3247 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003248 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003249
3250 err = trace__validate_ev_qualifier(&trace);
3251 if (err)
3252 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003253 }
3254
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003255 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003256 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003257 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003258 fprintf(trace.output, "%s", bf);
3259 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003260 }
3261
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003262 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003263 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003264 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003265 fprintf(trace.output, "%s", bf);
3266 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003267 }
3268
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003269 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003270 trace.opts.target.system_wide = true;
3271
David Ahern6810fc92013-08-28 22:29:52 -06003272 if (input_name)
3273 err = trace__replay(&trace);
3274 else
3275 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003276
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003277out_close:
3278 if (output_name != NULL)
3279 fclose(trace.output);
3280out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003281 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003282}