blob: abd5a94f5dbeb11f5bc4cd84db3db058a5797cc9 [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 Melo514f1c62012-09-26 20:05:56 -030049
Ingo Molnar456857b2013-09-12 15:29:00 +020050/* For older distros: */
Ingo Molnar456857b2013-09-12 15:29:00 +020051
Ben Hutchings79d26a62014-02-06 01:00:35 +000052#ifndef EFD_SEMAPHORE
53# define EFD_SEMAPHORE 1
54#endif
55
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030056#ifndef EFD_NONBLOCK
57# define EFD_NONBLOCK 00004000
58#endif
59
60#ifndef EFD_CLOEXEC
61# define EFD_CLOEXEC 02000000
62#endif
63
64#ifndef O_CLOEXEC
65# define O_CLOEXEC 02000000
66#endif
67
68#ifndef SOCK_DCCP
69# define SOCK_DCCP 6
70#endif
71
72#ifndef SOCK_CLOEXEC
73# define SOCK_CLOEXEC 02000000
74#endif
75
76#ifndef SOCK_NONBLOCK
77# define SOCK_NONBLOCK 00004000
78#endif
79
80#ifndef MSG_CMSG_CLOEXEC
81# define MSG_CMSG_CLOEXEC 0x40000000
82#endif
83
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -030084#ifndef PERF_FLAG_FD_NO_GROUP
85# define PERF_FLAG_FD_NO_GROUP (1UL << 0)
86#endif
87
88#ifndef PERF_FLAG_FD_OUTPUT
89# define PERF_FLAG_FD_OUTPUT (1UL << 1)
90#endif
91
92#ifndef PERF_FLAG_PID_CGROUP
93# define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */
94#endif
95
96#ifndef PERF_FLAG_FD_CLOEXEC
97# define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */
98#endif
99
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300100struct trace {
101 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300102 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300103 struct {
104 int max;
105 struct syscall *table;
106 struct {
107 struct perf_evsel *sys_enter,
108 *sys_exit;
109 } events;
110 } syscalls;
111 struct record_opts opts;
112 struct perf_evlist *evlist;
113 struct machine *host;
114 struct thread *current;
115 u64 base_time;
116 FILE *output;
117 unsigned long nr_events;
118 struct strlist *ev_qualifier;
119 struct {
120 size_t nr;
121 int *entries;
122 } ev_qualifier_ids;
123 struct intlist *tid_list;
124 struct intlist *pid_list;
125 struct {
126 size_t nr;
127 pid_t *entries;
128 } filter_pids;
129 double duration_filter;
130 double runtime_ms;
131 struct {
132 u64 vfs_getname,
133 proc_getname;
134 } stats;
135 bool not_ev_qualifier;
136 bool live;
137 bool full_time;
138 bool sched;
139 bool multiple_threads;
140 bool summary;
141 bool summary_only;
142 bool show_comm;
143 bool show_tool_stats;
144 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300145 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300146 bool force;
147 bool vfs_getname;
148 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300149 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300150};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300151
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300152struct tp_field {
153 int offset;
154 union {
155 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
156 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
157 };
158};
159
160#define TP_UINT_FIELD(bits) \
161static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
162{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500163 u##bits value; \
164 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
165 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300166}
167
168TP_UINT_FIELD(8);
169TP_UINT_FIELD(16);
170TP_UINT_FIELD(32);
171TP_UINT_FIELD(64);
172
173#define TP_UINT_FIELD__SWAPPED(bits) \
174static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
175{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500176 u##bits value; \
177 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300178 return bswap_##bits(value);\
179}
180
181TP_UINT_FIELD__SWAPPED(16);
182TP_UINT_FIELD__SWAPPED(32);
183TP_UINT_FIELD__SWAPPED(64);
184
185static int tp_field__init_uint(struct tp_field *field,
186 struct format_field *format_field,
187 bool needs_swap)
188{
189 field->offset = format_field->offset;
190
191 switch (format_field->size) {
192 case 1:
193 field->integer = tp_field__u8;
194 break;
195 case 2:
196 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
197 break;
198 case 4:
199 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
200 break;
201 case 8:
202 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
203 break;
204 default:
205 return -1;
206 }
207
208 return 0;
209}
210
211static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
212{
213 return sample->raw_data + field->offset;
214}
215
216static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
217{
218 field->offset = format_field->offset;
219 field->pointer = tp_field__ptr;
220 return 0;
221}
222
223struct syscall_tp {
224 struct tp_field id;
225 union {
226 struct tp_field args, ret;
227 };
228};
229
230static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
231 struct tp_field *field,
232 const char *name)
233{
234 struct format_field *format_field = perf_evsel__field(evsel, name);
235
236 if (format_field == NULL)
237 return -1;
238
239 return tp_field__init_uint(field, format_field, evsel->needs_swap);
240}
241
242#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
243 ({ struct syscall_tp *sc = evsel->priv;\
244 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
245
246static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
247 struct tp_field *field,
248 const char *name)
249{
250 struct format_field *format_field = perf_evsel__field(evsel, name);
251
252 if (format_field == NULL)
253 return -1;
254
255 return tp_field__init_ptr(field, format_field);
256}
257
258#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
259 ({ struct syscall_tp *sc = evsel->priv;\
260 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
261
262static void perf_evsel__delete_priv(struct perf_evsel *evsel)
263{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300264 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300265 perf_evsel__delete(evsel);
266}
267
Namhyung Kim96695d42013-11-12 08:51:45 -0300268static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
269{
270 evsel->priv = malloc(sizeof(struct syscall_tp));
271 if (evsel->priv != NULL) {
272 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
273 goto out_delete;
274
275 evsel->handler = handler;
276 return 0;
277 }
278
279 return -ENOMEM;
280
281out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300282 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300283 return -ENOENT;
284}
285
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300286static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300287{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300288 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300289
David Ahern9aca7f12013-12-04 19:41:39 -0700290 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200291 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700292 evsel = perf_evsel__newtp("syscalls", direction);
293
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200294 if (IS_ERR(evsel))
295 return NULL;
296
297 if (perf_evsel__init_syscall_tp(evsel, handler))
298 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300299
300 return evsel;
301
302out_delete:
303 perf_evsel__delete_priv(evsel);
304 return NULL;
305}
306
307#define perf_evsel__sc_tp_uint(evsel, name, sample) \
308 ({ struct syscall_tp *fields = evsel->priv; \
309 fields->name.integer(&fields->name, sample); })
310
311#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
312 ({ struct syscall_tp *fields = evsel->priv; \
313 fields->name.pointer(&fields->name, sample); })
314
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300315struct syscall_arg {
316 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300317 struct thread *thread;
318 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300319 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300320 u8 idx;
321 u8 mask;
322};
323
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300324struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300325 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300326 int nr_entries;
327 const char **entries;
328};
329
330#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
331 .nr_entries = ARRAY_SIZE(array), \
332 .entries = array, \
333}
334
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300335#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
336 .offset = off, \
337 .nr_entries = ARRAY_SIZE(array), \
338 .entries = array, \
339}
340
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300341static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
342 const char *intfmt,
343 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300344{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300345 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300346 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300347
348 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300349 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300350
351 return scnprintf(bf, size, "%s", sa->entries[idx]);
352}
353
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300354static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
355 struct syscall_arg *arg)
356{
357 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
358}
359
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300360#define SCA_STRARRAY syscall_arg__scnprintf_strarray
361
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300362#if defined(__i386__) || defined(__x86_64__)
363/*
364 * FIXME: Make this available to all arches as soon as the ioctl beautifier
365 * gets rewritten to support all arches.
366 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300367static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
368 struct syscall_arg *arg)
369{
370 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
371}
372
373#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300374#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300375
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300376static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
377 struct syscall_arg *arg);
378
379#define SCA_FD syscall_arg__scnprintf_fd
380
381static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
382 struct syscall_arg *arg)
383{
384 int fd = arg->val;
385
386 if (fd == AT_FDCWD)
387 return scnprintf(bf, size, "CWD");
388
389 return syscall_arg__scnprintf_fd(bf, size, arg);
390}
391
392#define SCA_FDAT syscall_arg__scnprintf_fd_at
393
394static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
395 struct syscall_arg *arg);
396
397#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
398
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300399static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300400 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300401{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300402 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300403}
404
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300405#define SCA_HEX syscall_arg__scnprintf_hex
406
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300407static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
408 struct syscall_arg *arg)
409{
410 return scnprintf(bf, size, "%d", arg->val);
411}
412
413#define SCA_INT syscall_arg__scnprintf_int
414
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300415static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
416 struct syscall_arg *arg)
417{
418 int printed = 0, op = arg->val;
419
420 if (op == 0)
421 return scnprintf(bf, size, "NONE");
422#define P_CMD(cmd) \
423 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
424 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
425 op &= ~LOCK_##cmd; \
426 }
427
428 P_CMD(SH);
429 P_CMD(EX);
430 P_CMD(NB);
431 P_CMD(UN);
432 P_CMD(MAND);
433 P_CMD(RW);
434 P_CMD(READ);
435 P_CMD(WRITE);
436#undef P_OP
437
438 if (op)
439 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
440
441 return printed;
442}
443
444#define SCA_FLOCK syscall_arg__scnprintf_flock
445
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300446static 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 -0300447{
448 enum syscall_futex_args {
449 SCF_UADDR = (1 << 0),
450 SCF_OP = (1 << 1),
451 SCF_VAL = (1 << 2),
452 SCF_TIMEOUT = (1 << 3),
453 SCF_UADDR2 = (1 << 4),
454 SCF_VAL3 = (1 << 5),
455 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300456 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300457 int cmd = op & FUTEX_CMD_MASK;
458 size_t printed = 0;
459
460 switch (cmd) {
461#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300462 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
463 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
464 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
465 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
466 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
467 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300468 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300469 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
470 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
471 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
472 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
473 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300474 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
475 default: printed = scnprintf(bf, size, "%#x", cmd); break;
476 }
477
478 if (op & FUTEX_PRIVATE_FLAG)
479 printed += scnprintf(bf + printed, size - printed, "|PRIV");
480
481 if (op & FUTEX_CLOCK_REALTIME)
482 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
483
484 return printed;
485}
486
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300487#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
488
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300489static const char *bpf_cmd[] = {
490 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
491 "MAP_GET_NEXT_KEY", "PROG_LOAD",
492};
493static DEFINE_STRARRAY(bpf_cmd);
494
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300495static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
496static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300497
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300498static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
499static DEFINE_STRARRAY(itimers);
500
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300501static const char *keyctl_options[] = {
502 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
503 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
504 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
505 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
506 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
507};
508static DEFINE_STRARRAY(keyctl_options);
509
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300510static const char *whences[] = { "SET", "CUR", "END",
511#ifdef SEEK_DATA
512"DATA",
513#endif
514#ifdef SEEK_HOLE
515"HOLE",
516#endif
517};
518static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300519
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300520static const char *fcntl_cmds[] = {
521 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
522 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
523 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
524 "F_GETOWNER_UIDS",
525};
526static DEFINE_STRARRAY(fcntl_cmds);
527
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300528static const char *rlimit_resources[] = {
529 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
530 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
531 "RTTIME",
532};
533static DEFINE_STRARRAY(rlimit_resources);
534
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300535static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
536static DEFINE_STRARRAY(sighow);
537
David Ahern4f8c1b72013-09-22 19:45:00 -0600538static const char *clockid[] = {
539 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300540 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
541 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600542};
543static DEFINE_STRARRAY(clockid);
544
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300545static const char *socket_families[] = {
546 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
547 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
548 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
549 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
550 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
551 "ALG", "NFC", "VSOCK",
552};
553static DEFINE_STRARRAY(socket_families);
554
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300555#ifndef SOCK_TYPE_MASK
556#define SOCK_TYPE_MASK 0xf
557#endif
558
559static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
560 struct syscall_arg *arg)
561{
562 size_t printed;
563 int type = arg->val,
564 flags = type & ~SOCK_TYPE_MASK;
565
566 type &= SOCK_TYPE_MASK;
567 /*
568 * Can't use a strarray, MIPS may override for ABI reasons.
569 */
570 switch (type) {
571#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
572 P_SK_TYPE(STREAM);
573 P_SK_TYPE(DGRAM);
574 P_SK_TYPE(RAW);
575 P_SK_TYPE(RDM);
576 P_SK_TYPE(SEQPACKET);
577 P_SK_TYPE(DCCP);
578 P_SK_TYPE(PACKET);
579#undef P_SK_TYPE
580 default:
581 printed = scnprintf(bf, size, "%#x", type);
582 }
583
584#define P_SK_FLAG(n) \
585 if (flags & SOCK_##n) { \
586 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
587 flags &= ~SOCK_##n; \
588 }
589
590 P_SK_FLAG(CLOEXEC);
591 P_SK_FLAG(NONBLOCK);
592#undef P_SK_FLAG
593
594 if (flags)
595 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
596
597 return printed;
598}
599
600#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
601
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300602#ifndef MSG_PROBE
603#define MSG_PROBE 0x10
604#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600605#ifndef MSG_WAITFORONE
606#define MSG_WAITFORONE 0x10000
607#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300608#ifndef MSG_SENDPAGE_NOTLAST
609#define MSG_SENDPAGE_NOTLAST 0x20000
610#endif
611#ifndef MSG_FASTOPEN
612#define MSG_FASTOPEN 0x20000000
613#endif
614
615static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
616 struct syscall_arg *arg)
617{
618 int printed = 0, flags = arg->val;
619
620 if (flags == 0)
621 return scnprintf(bf, size, "NONE");
622#define P_MSG_FLAG(n) \
623 if (flags & MSG_##n) { \
624 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
625 flags &= ~MSG_##n; \
626 }
627
628 P_MSG_FLAG(OOB);
629 P_MSG_FLAG(PEEK);
630 P_MSG_FLAG(DONTROUTE);
631 P_MSG_FLAG(TRYHARD);
632 P_MSG_FLAG(CTRUNC);
633 P_MSG_FLAG(PROBE);
634 P_MSG_FLAG(TRUNC);
635 P_MSG_FLAG(DONTWAIT);
636 P_MSG_FLAG(EOR);
637 P_MSG_FLAG(WAITALL);
638 P_MSG_FLAG(FIN);
639 P_MSG_FLAG(SYN);
640 P_MSG_FLAG(CONFIRM);
641 P_MSG_FLAG(RST);
642 P_MSG_FLAG(ERRQUEUE);
643 P_MSG_FLAG(NOSIGNAL);
644 P_MSG_FLAG(MORE);
645 P_MSG_FLAG(WAITFORONE);
646 P_MSG_FLAG(SENDPAGE_NOTLAST);
647 P_MSG_FLAG(FASTOPEN);
648 P_MSG_FLAG(CMSG_CLOEXEC);
649#undef P_MSG_FLAG
650
651 if (flags)
652 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
653
654 return printed;
655}
656
657#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
658
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300659static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
660 struct syscall_arg *arg)
661{
662 size_t printed = 0;
663 int mode = arg->val;
664
665 if (mode == F_OK) /* 0 */
666 return scnprintf(bf, size, "F");
667#define P_MODE(n) \
668 if (mode & n##_OK) { \
669 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
670 mode &= ~n##_OK; \
671 }
672
673 P_MODE(R);
674 P_MODE(W);
675 P_MODE(X);
676#undef P_MODE
677
678 if (mode)
679 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
680
681 return printed;
682}
683
684#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
685
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300686static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
687 struct syscall_arg *arg);
688
689#define SCA_FILENAME syscall_arg__scnprintf_filename
690
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300691static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300692 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300693{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300694 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300695
696 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300697 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300698
699 if (flags == 0)
700 return scnprintf(bf, size, "RDONLY");
701#define P_FLAG(n) \
702 if (flags & O_##n) { \
703 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
704 flags &= ~O_##n; \
705 }
706
707 P_FLAG(APPEND);
708 P_FLAG(ASYNC);
709 P_FLAG(CLOEXEC);
710 P_FLAG(CREAT);
711 P_FLAG(DIRECT);
712 P_FLAG(DIRECTORY);
713 P_FLAG(EXCL);
714 P_FLAG(LARGEFILE);
715 P_FLAG(NOATIME);
716 P_FLAG(NOCTTY);
717#ifdef O_NONBLOCK
718 P_FLAG(NONBLOCK);
719#elif O_NDELAY
720 P_FLAG(NDELAY);
721#endif
722#ifdef O_PATH
723 P_FLAG(PATH);
724#endif
725 P_FLAG(RDWR);
726#ifdef O_DSYNC
727 if ((flags & O_SYNC) == O_SYNC)
728 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
729 else {
730 P_FLAG(DSYNC);
731 }
732#else
733 P_FLAG(SYNC);
734#endif
735 P_FLAG(TRUNC);
736 P_FLAG(WRONLY);
737#undef P_FLAG
738
739 if (flags)
740 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
741
742 return printed;
743}
744
745#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
746
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300747static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size,
748 struct syscall_arg *arg)
749{
750 int printed = 0, flags = arg->val;
751
752 if (flags == 0)
753 return 0;
754
755#define P_FLAG(n) \
756 if (flags & PERF_FLAG_##n) { \
757 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
758 flags &= ~PERF_FLAG_##n; \
759 }
760
761 P_FLAG(FD_NO_GROUP);
762 P_FLAG(FD_OUTPUT);
763 P_FLAG(PID_CGROUP);
764 P_FLAG(FD_CLOEXEC);
765#undef P_FLAG
766
767 if (flags)
768 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
769
770 return printed;
771}
772
773#define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags
774
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300775static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
776 struct syscall_arg *arg)
777{
778 int printed = 0, flags = arg->val;
779
780 if (flags == 0)
781 return scnprintf(bf, size, "NONE");
782#define P_FLAG(n) \
783 if (flags & EFD_##n) { \
784 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
785 flags &= ~EFD_##n; \
786 }
787
788 P_FLAG(SEMAPHORE);
789 P_FLAG(CLOEXEC);
790 P_FLAG(NONBLOCK);
791#undef P_FLAG
792
793 if (flags)
794 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
795
796 return printed;
797}
798
799#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
800
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300801static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
802 struct syscall_arg *arg)
803{
804 int printed = 0, flags = arg->val;
805
806#define P_FLAG(n) \
807 if (flags & O_##n) { \
808 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
809 flags &= ~O_##n; \
810 }
811
812 P_FLAG(CLOEXEC);
813 P_FLAG(NONBLOCK);
814#undef P_FLAG
815
816 if (flags)
817 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
818
819 return printed;
820}
821
822#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
823
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300824static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
825{
826 int sig = arg->val;
827
828 switch (sig) {
829#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
830 P_SIGNUM(HUP);
831 P_SIGNUM(INT);
832 P_SIGNUM(QUIT);
833 P_SIGNUM(ILL);
834 P_SIGNUM(TRAP);
835 P_SIGNUM(ABRT);
836 P_SIGNUM(BUS);
837 P_SIGNUM(FPE);
838 P_SIGNUM(KILL);
839 P_SIGNUM(USR1);
840 P_SIGNUM(SEGV);
841 P_SIGNUM(USR2);
842 P_SIGNUM(PIPE);
843 P_SIGNUM(ALRM);
844 P_SIGNUM(TERM);
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300845 P_SIGNUM(CHLD);
846 P_SIGNUM(CONT);
847 P_SIGNUM(STOP);
848 P_SIGNUM(TSTP);
849 P_SIGNUM(TTIN);
850 P_SIGNUM(TTOU);
851 P_SIGNUM(URG);
852 P_SIGNUM(XCPU);
853 P_SIGNUM(XFSZ);
854 P_SIGNUM(VTALRM);
855 P_SIGNUM(PROF);
856 P_SIGNUM(WINCH);
857 P_SIGNUM(IO);
858 P_SIGNUM(PWR);
859 P_SIGNUM(SYS);
Ben Hutchings02c5bb42014-02-06 01:00:41 +0000860#ifdef SIGEMT
861 P_SIGNUM(EMT);
862#endif
863#ifdef SIGSTKFLT
864 P_SIGNUM(STKFLT);
865#endif
866#ifdef SIGSWI
867 P_SIGNUM(SWI);
868#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300869 default: break;
870 }
871
872 return scnprintf(bf, size, "%#x", sig);
873}
874
875#define SCA_SIGNUM syscall_arg__scnprintf_signum
876
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300877#if defined(__i386__) || defined(__x86_64__)
878/*
879 * FIXME: Make this available to all arches.
880 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300881#define TCGETS 0x5401
882
883static const char *tioctls[] = {
884 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
885 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
886 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
887 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
888 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
889 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
890 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
891 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
892 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
893 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
894 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
895 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
896 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
897 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
898 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
899};
900
901static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300902#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300903
Arnaldo Carvalho de Melo6fb35b92016-04-13 11:50:23 -0300904#ifndef SECCOMP_SET_MODE_STRICT
905#define SECCOMP_SET_MODE_STRICT 0
906#endif
907#ifndef SECCOMP_SET_MODE_FILTER
908#define SECCOMP_SET_MODE_FILTER 1
909#endif
910
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300911static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg)
912{
913 int op = arg->val;
914 size_t printed = 0;
915
916 switch (op) {
917#define P_SECCOMP_SET_MODE_OP(n) case SECCOMP_SET_MODE_##n: printed = scnprintf(bf, size, #n); break
918 P_SECCOMP_SET_MODE_OP(STRICT);
919 P_SECCOMP_SET_MODE_OP(FILTER);
920#undef P_SECCOMP_SET_MODE_OP
921 default: printed = scnprintf(bf, size, "%#x", op); break;
922 }
923
924 return printed;
925}
926
927#define SCA_SECCOMP_OP syscall_arg__scnprintf_seccomp_op
928
Arnaldo Carvalho de Melo6fb35b92016-04-13 11:50:23 -0300929#ifndef SECCOMP_FILTER_FLAG_TSYNC
930#define SECCOMP_FILTER_FLAG_TSYNC 1
931#endif
932
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300933static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size,
934 struct syscall_arg *arg)
935{
936 int printed = 0, flags = arg->val;
937
938#define P_FLAG(n) \
939 if (flags & SECCOMP_FILTER_FLAG_##n) { \
940 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
941 flags &= ~SECCOMP_FILTER_FLAG_##n; \
942 }
943
944 P_FLAG(TSYNC);
945#undef P_FLAG
946
947 if (flags)
948 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
949
950 return printed;
951}
952
953#define SCA_SECCOMP_FLAGS syscall_arg__scnprintf_seccomp_flags
954
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300955#ifndef GRND_NONBLOCK
956#define GRND_NONBLOCK 0x0001
957#endif
958#ifndef GRND_RANDOM
959#define GRND_RANDOM 0x0002
960#endif
961
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300962static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
963 struct syscall_arg *arg)
964{
965 int printed = 0, flags = arg->val;
966
967#define P_FLAG(n) \
968 if (flags & GRND_##n) { \
969 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
970 flags &= ~GRND_##n; \
971 }
972
973 P_FLAG(RANDOM);
974 P_FLAG(NONBLOCK);
975#undef P_FLAG
976
977 if (flags)
978 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
979
980 return printed;
981}
982
983#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
984
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300985#define STRARRAY(arg, name, array) \
986 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
987 .arg_parm = { [arg] = &strarray__##array, }
988
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300989#include "trace/beauty/pid.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300990#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300991#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300992#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300993#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300994
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300995static struct syscall_fmt {
996 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300997 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300998 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300999 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001000 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001001 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001002 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001003 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001004} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -03001005 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001006 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1007 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001008 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -03001009 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001010 { .name = "brk", .hexret = true,
1011 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001012 { .name = "chdir", .errmsg = true,
1013 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1014 { .name = "chmod", .errmsg = true,
1015 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1016 { .name = "chroot", .errmsg = true,
1017 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -06001018 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001019 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001020 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001021 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -03001022 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001023 { .name = "creat", .errmsg = true,
1024 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001025 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001026 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001027 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001028 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001029 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001030 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001031 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -03001032 { .name = "eventfd2", .errmsg = true,
1033 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001034 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001035 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1036 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001037 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001038 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001039 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001040 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001041 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001042 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001043 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001044 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001045 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001046 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1047 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001048 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001049 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001050 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001051 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1052 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001053 { .name = "fcntl", .errmsg = true,
1054 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1055 [1] = SCA_STRARRAY, /* cmd */ },
1056 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1057 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001058 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -03001059 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001060 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1061 [1] = SCA_FLOCK, /* cmd */ }, },
1062 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001063 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001064 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001065 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001066 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001067 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1068 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001069 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001070 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001071 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001072 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001073 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001074 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -03001075 { .name = "futex", .errmsg = true,
1076 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001077 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001078 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1079 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001080 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001081 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001082 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001083 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001084 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001085 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001086 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001087 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -03001088 { .name = "getrandom", .errmsg = true,
1089 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001090 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001091 { .name = "getxattr", .errmsg = true,
1092 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1093 { .name = "inotify_add_watch", .errmsg = true,
1094 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001095 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001096 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001097#if defined(__i386__) || defined(__x86_64__)
1098/*
1099 * FIXME: Make this available to all arches.
1100 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001101 [1] = SCA_STRHEXARRAY, /* cmd */
1102 [2] = SCA_HEX, /* arg */ },
1103 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001104#else
1105 [2] = SCA_HEX, /* arg */ }, },
1106#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -03001107 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001108 { .name = "kill", .errmsg = true,
1109 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001110 { .name = "lchown", .errmsg = true,
1111 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1112 { .name = "lgetxattr", .errmsg = true,
1113 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001114 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001115 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001116 { .name = "listxattr", .errmsg = true,
1117 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001118 { .name = "llistxattr", .errmsg = true,
1119 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1120 { .name = "lremovexattr", .errmsg = true,
1121 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001122 { .name = "lseek", .errmsg = true,
1123 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1124 [2] = SCA_STRARRAY, /* whence */ },
1125 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001126 { .name = "lsetxattr", .errmsg = true,
1127 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001128 { .name = "lstat", .errmsg = true, .alias = "newlstat",
1129 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001130 { .name = "lsxattr", .errmsg = true,
1131 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001132 { .name = "madvise", .errmsg = true,
1133 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1134 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001135 { .name = "mkdir", .errmsg = true,
1136 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001137 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001138 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1139 [1] = SCA_FILENAME, /* pathname */ }, },
1140 { .name = "mknod", .errmsg = true,
1141 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001142 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001143 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1144 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001145 { .name = "mlock", .errmsg = true,
1146 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1147 { .name = "mlockall", .errmsg = true,
1148 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001149 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001150 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001151 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001152 [3] = SCA_MMAP_FLAGS, /* flags */
1153 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001154 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001155 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1156 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001157 { .name = "mq_unlink", .errmsg = true,
1158 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001159 { .name = "mremap", .hexret = true,
1160 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001161 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001162 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001163 { .name = "munlock", .errmsg = true,
1164 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001165 { .name = "munmap", .errmsg = true,
1166 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001167 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001168 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001169 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001170 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1171 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001172 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001173 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1174 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001175 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001176 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1177 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001178 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001179 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001180 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001181 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001182 { .name = "perf_event_open", .errmsg = true,
1183 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1184 [2] = SCA_INT, /* cpu */
1185 [3] = SCA_FD, /* group_fd */
1186 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001187 { .name = "pipe2", .errmsg = true,
1188 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001189 { .name = "poll", .errmsg = true, .timeout = true, },
1190 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001191 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001192 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001193 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001194 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001195 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001196 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001197 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001198 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001199 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001200 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001201 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001202 { .name = "readlink", .errmsg = true,
1203 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001204 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001205 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1206 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001207 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001208 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001209 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001210 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1211 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001212 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001213 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1214 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001215 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001216 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1217 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001218 { .name = "removexattr", .errmsg = true,
1219 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001220 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001221 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001222 { .name = "rmdir", .errmsg = true,
1223 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001224 { .name = "rt_sigaction", .errmsg = true,
1225 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001226 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001227 { .name = "rt_sigqueueinfo", .errmsg = true,
1228 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1229 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1230 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001231 { .name = "sched_setscheduler", .errmsg = true,
1232 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001233 { .name = "seccomp", .errmsg = true,
1234 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
1235 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001236 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001237 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001238 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1239 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001240 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001241 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1242 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001243 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001244 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1245 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001246 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001247 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001248 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001249 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001250 { .name = "setxattr", .errmsg = true,
1251 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001252 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001253 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001254 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001255 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1256 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001257 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001258 { .name = "socketpair", .errmsg = true,
1259 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1260 [1] = SCA_SK_TYPE, /* type */ },
1261 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001262 { .name = "stat", .errmsg = true, .alias = "newstat",
1263 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001264 { .name = "statfs", .errmsg = true,
1265 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1266 { .name = "swapoff", .errmsg = true,
1267 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1268 { .name = "swapon", .errmsg = true,
1269 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001270 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001271 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001272 { .name = "tgkill", .errmsg = true,
1273 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1274 { .name = "tkill", .errmsg = true,
1275 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001276 { .name = "truncate", .errmsg = true,
1277 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001278 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001279 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001280 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1281 [1] = SCA_FILENAME, /* pathname */ }, },
1282 { .name = "utime", .errmsg = true,
1283 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001284 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001285 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1286 [1] = SCA_FILENAME, /* filename */ }, },
1287 { .name = "utimes", .errmsg = true,
1288 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001289 { .name = "vmsplice", .errmsg = true,
1290 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001291 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001292 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001293 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001294 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001295 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001296 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001297 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001298 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001299};
1300
1301static int syscall_fmt__cmp(const void *name, const void *fmtp)
1302{
1303 const struct syscall_fmt *fmt = fmtp;
1304 return strcmp(name, fmt->name);
1305}
1306
1307static struct syscall_fmt *syscall_fmt__find(const char *name)
1308{
1309 const int nmemb = ARRAY_SIZE(syscall_fmts);
1310 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1311}
1312
1313struct syscall {
1314 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001315 int nr_args;
1316 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001317 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001318 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001319 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001320 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001321 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001322};
1323
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001324static size_t fprintf_duration(unsigned long t, FILE *fp)
1325{
1326 double duration = (double)t / NSEC_PER_MSEC;
1327 size_t printed = fprintf(fp, "(");
1328
1329 if (duration >= 1.0)
1330 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1331 else if (duration >= 0.01)
1332 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1333 else
1334 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001335 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001336}
1337
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001338/**
1339 * filename.ptr: The filename char pointer that will be vfs_getname'd
1340 * filename.entry_str_pos: Where to insert the string translated from
1341 * filename.ptr by the vfs_getname tracepoint/kprobe.
1342 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001343struct thread_trace {
1344 u64 entry_time;
1345 u64 exit_time;
1346 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001347 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001348 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001349 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001350 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001351 struct {
1352 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001353 short int entry_str_pos;
1354 bool pending_open;
1355 unsigned int namelen;
1356 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001357 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001358 struct {
1359 int max;
1360 char **table;
1361 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001362
1363 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001364};
1365
1366static struct thread_trace *thread_trace__new(void)
1367{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001368 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1369
1370 if (ttrace)
1371 ttrace->paths.max = -1;
1372
David Ahernbf2575c2013-10-08 21:26:53 -06001373 ttrace->syscall_stats = intlist__new(NULL);
1374
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001375 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001376}
1377
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001378static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001379{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001380 struct thread_trace *ttrace;
1381
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001382 if (thread == NULL)
1383 goto fail;
1384
Namhyung Kim89dceb22014-10-06 09:46:03 +09001385 if (thread__priv(thread) == NULL)
1386 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001387
Namhyung Kim89dceb22014-10-06 09:46:03 +09001388 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001389 goto fail;
1390
Namhyung Kim89dceb22014-10-06 09:46:03 +09001391 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001392 ++ttrace->nr_events;
1393
1394 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001395fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001396 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001397 "WARNING: not enough memory, dropping samples!\n");
1398 return NULL;
1399}
1400
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001401#define TRACE_PFMAJ (1 << 0)
1402#define TRACE_PFMIN (1 << 1)
1403
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001404static const size_t trace__entry_str_size = 2048;
1405
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001406static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001407{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001408 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001409
1410 if (fd > ttrace->paths.max) {
1411 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1412
1413 if (npath == NULL)
1414 return -1;
1415
1416 if (ttrace->paths.max != -1) {
1417 memset(npath + ttrace->paths.max + 1, 0,
1418 (fd - ttrace->paths.max) * sizeof(char *));
1419 } else {
1420 memset(npath, 0, (fd + 1) * sizeof(char *));
1421 }
1422
1423 ttrace->paths.table = npath;
1424 ttrace->paths.max = fd;
1425 }
1426
1427 ttrace->paths.table[fd] = strdup(pathname);
1428
1429 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1430}
1431
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001432static int thread__read_fd_path(struct thread *thread, int fd)
1433{
1434 char linkname[PATH_MAX], pathname[PATH_MAX];
1435 struct stat st;
1436 int ret;
1437
1438 if (thread->pid_ == thread->tid) {
1439 scnprintf(linkname, sizeof(linkname),
1440 "/proc/%d/fd/%d", thread->pid_, fd);
1441 } else {
1442 scnprintf(linkname, sizeof(linkname),
1443 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1444 }
1445
1446 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1447 return -1;
1448
1449 ret = readlink(linkname, pathname, sizeof(pathname));
1450
1451 if (ret < 0 || ret > st.st_size)
1452 return -1;
1453
1454 pathname[ret] = '\0';
1455 return trace__set_fd_pathname(thread, fd, pathname);
1456}
1457
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001458static const char *thread__fd_path(struct thread *thread, int fd,
1459 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001460{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001461 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001462
1463 if (ttrace == NULL)
1464 return NULL;
1465
1466 if (fd < 0)
1467 return NULL;
1468
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001469 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001470 if (!trace->live)
1471 return NULL;
1472 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001473 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001474 return NULL;
1475 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001476
1477 return ttrace->paths.table[fd];
1478}
1479
1480static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1481 struct syscall_arg *arg)
1482{
1483 int fd = arg->val;
1484 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001485 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001486
1487 if (path)
1488 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1489
1490 return printed;
1491}
1492
1493static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1494 struct syscall_arg *arg)
1495{
1496 int fd = arg->val;
1497 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001498 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001499
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001500 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1501 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001502
1503 return printed;
1504}
1505
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001506static void thread__set_filename_pos(struct thread *thread, const char *bf,
1507 unsigned long ptr)
1508{
1509 struct thread_trace *ttrace = thread__priv(thread);
1510
1511 ttrace->filename.ptr = ptr;
1512 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1513}
1514
1515static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1516 struct syscall_arg *arg)
1517{
1518 unsigned long ptr = arg->val;
1519
1520 if (!arg->trace->vfs_getname)
1521 return scnprintf(bf, size, "%#x", ptr);
1522
1523 thread__set_filename_pos(arg->thread, bf, ptr);
1524 return 0;
1525}
1526
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001527static bool trace__filter_duration(struct trace *trace, double t)
1528{
1529 return t < (trace->duration_filter * NSEC_PER_MSEC);
1530}
1531
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001532static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1533{
1534 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1535
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001536 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001537}
1538
Namhyung Kimf15eb532012-10-05 14:02:16 +09001539static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001540static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001541
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001542static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001543{
1544 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001545 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001546}
1547
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001548static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001549 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001550{
1551 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001552 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001553
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001554 if (trace->multiple_threads) {
1555 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001556 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001557 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001558 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001559
1560 return printed;
1561}
1562
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001563static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001564 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001565{
1566 int ret = 0;
1567
1568 switch (event->header.type) {
1569 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001570 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001571 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001572 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001573 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001574 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001575 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001576 break;
1577 }
1578
1579 return ret;
1580}
1581
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001582static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001583 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001584 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001585 struct machine *machine)
1586{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001587 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001588 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001589}
1590
1591static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1592{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001593 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001594
1595 if (err)
1596 return err;
1597
David Ahern8fb598e2013-09-28 13:13:00 -06001598 trace->host = machine__new_host();
1599 if (trace->host == NULL)
1600 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001601
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001602 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001603 return -errno;
1604
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001605 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001606 evlist->threads, trace__tool_process, false,
1607 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001608 if (err)
1609 symbol__exit();
1610
1611 return err;
1612}
1613
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001614static int syscall__set_arg_fmts(struct syscall *sc)
1615{
1616 struct format_field *field;
1617 int idx = 0;
1618
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001619 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001620 if (sc->arg_scnprintf == NULL)
1621 return -1;
1622
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001623 if (sc->fmt)
1624 sc->arg_parm = sc->fmt->arg_parm;
1625
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001626 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001627 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1628 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1629 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001630 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001631 else if (strcmp(field->type, "pid_t") == 0)
1632 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001633 else if (strcmp(field->type, "umode_t") == 0)
1634 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001635 ++idx;
1636 }
1637
1638 return 0;
1639}
1640
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001641static int trace__read_syscall_info(struct trace *trace, int id)
1642{
1643 char tp_name[128];
1644 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001645 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001646
1647 if (name == NULL)
1648 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001649
1650 if (id > trace->syscalls.max) {
1651 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1652
1653 if (nsyscalls == NULL)
1654 return -1;
1655
1656 if (trace->syscalls.max != -1) {
1657 memset(nsyscalls + trace->syscalls.max + 1, 0,
1658 (id - trace->syscalls.max) * sizeof(*sc));
1659 } else {
1660 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1661 }
1662
1663 trace->syscalls.table = nsyscalls;
1664 trace->syscalls.max = id;
1665 }
1666
1667 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001668 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001669
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001670 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001671
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001672 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001673 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001674
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001675 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001676 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001677 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001678 }
1679
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001680 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001681 return -1;
1682
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001683 sc->args = sc->tp_format->format.fields;
1684 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001685 /*
1686 * We need to check and discard the first variable '__syscall_nr'
1687 * or 'nr' that mean the syscall number. It is needless here.
1688 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1689 */
1690 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001691 sc->args = sc->args->next;
1692 --sc->nr_args;
1693 }
1694
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001695 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1696
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001697 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001698}
1699
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001700static int trace__validate_ev_qualifier(struct trace *trace)
1701{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001702 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001703 struct str_node *pos;
1704
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001705 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1706 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1707 sizeof(trace->ev_qualifier_ids.entries[0]));
1708
1709 if (trace->ev_qualifier_ids.entries == NULL) {
1710 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1711 trace->output);
1712 err = -EINVAL;
1713 goto out;
1714 }
1715
1716 i = 0;
1717
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001718 strlist__for_each(pos, trace->ev_qualifier) {
1719 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001720 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001721
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001722 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001723 if (err == 0) {
1724 fputs("Error:\tInvalid syscall ", trace->output);
1725 err = -EINVAL;
1726 } else {
1727 fputs(", ", trace->output);
1728 }
1729
1730 fputs(sc, trace->output);
1731 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001732
1733 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001734 }
1735
1736 if (err < 0) {
1737 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1738 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001739 zfree(&trace->ev_qualifier_ids.entries);
1740 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001741 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001742out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001743 return err;
1744}
1745
David Ahern55d43bca2015-02-19 15:00:22 -05001746/*
1747 * args is to be interpreted as a series of longs but we need to handle
1748 * 8-byte unaligned accesses. args points to raw_data within the event
1749 * and raw_data is guaranteed to be 8-byte unaligned because it is
1750 * preceded by raw_size which is a u32. So we need to copy args to a temp
1751 * variable to read it. Most notably this avoids extended load instructions
1752 * on unaligned addresses
1753 */
1754
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001755static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001756 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001757 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001758{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001759 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001760 unsigned char *p;
1761 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001762
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001763 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001764 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001765 u8 bit = 1;
1766 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001767 .idx = 0,
1768 .mask = 0,
1769 .trace = trace,
1770 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001771 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001772
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001773 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001774 field = field->next, ++arg.idx, bit <<= 1) {
1775 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001776 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001777
1778 /* special care for unaligned accesses */
1779 p = args + sizeof(unsigned long) * arg.idx;
1780 memcpy(&val, p, sizeof(val));
1781
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001782 /*
1783 * Suppress this argument if its value is zero and
1784 * and we don't have a string associated in an
1785 * strarray for it.
1786 */
David Ahern55d43bca2015-02-19 15:00:22 -05001787 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001788 !(sc->arg_scnprintf &&
1789 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1790 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001791 continue;
1792
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001793 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001794 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001795 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bca2015-02-19 15:00:22 -05001796 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001797 if (sc->arg_parm)
1798 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001799 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1800 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001801 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001802 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bca2015-02-19 15:00:22 -05001803 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001804 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001805 }
1806 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001807 int i = 0;
1808
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001809 while (i < 6) {
David Ahern55d43bca2015-02-19 15:00:22 -05001810 /* special care for unaligned accesses */
1811 p = args + sizeof(unsigned long) * i;
1812 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001813 printed += scnprintf(bf + printed, size - printed,
1814 "%sarg%d: %ld",
David Ahern55d43bca2015-02-19 15:00:22 -05001815 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001816 ++i;
1817 }
1818 }
1819
1820 return printed;
1821}
1822
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001823typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001824 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001825 struct perf_sample *sample);
1826
1827static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001828 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001829{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001830
1831 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001832
1833 /*
1834 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1835 * before that, leaving at a higher verbosity level till that is
1836 * explained. Reproduced with plain ftrace with:
1837 *
1838 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1839 * grep "NR -1 " /t/trace_pipe
1840 *
1841 * After generating some load on the machine.
1842 */
1843 if (verbose > 1) {
1844 static u64 n;
1845 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1846 id, perf_evsel__name(evsel), ++n);
1847 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001848 return NULL;
1849 }
1850
1851 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1852 trace__read_syscall_info(trace, id))
1853 goto out_cant_read;
1854
1855 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1856 goto out_cant_read;
1857
1858 return &trace->syscalls.table[id];
1859
1860out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001861 if (verbose) {
1862 fprintf(trace->output, "Problems reading syscall %d", id);
1863 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1864 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1865 fputs(" information\n", trace->output);
1866 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001867 return NULL;
1868}
1869
David Ahernbf2575c2013-10-08 21:26:53 -06001870static void thread__update_stats(struct thread_trace *ttrace,
1871 int id, struct perf_sample *sample)
1872{
1873 struct int_node *inode;
1874 struct stats *stats;
1875 u64 duration = 0;
1876
1877 inode = intlist__findnew(ttrace->syscall_stats, id);
1878 if (inode == NULL)
1879 return;
1880
1881 stats = inode->priv;
1882 if (stats == NULL) {
1883 stats = malloc(sizeof(struct stats));
1884 if (stats == NULL)
1885 return;
1886 init_stats(stats);
1887 inode->priv = stats;
1888 }
1889
1890 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1891 duration = sample->time - ttrace->entry_time;
1892
1893 update_stats(stats, duration);
1894}
1895
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001896static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1897{
1898 struct thread_trace *ttrace;
1899 u64 duration;
1900 size_t printed;
1901
1902 if (trace->current == NULL)
1903 return 0;
1904
1905 ttrace = thread__priv(trace->current);
1906
1907 if (!ttrace->entry_pending)
1908 return 0;
1909
1910 duration = sample->time - ttrace->entry_time;
1911
1912 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1913 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1914 ttrace->entry_pending = false;
1915
1916 return printed;
1917}
1918
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001919static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001920 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001921 struct perf_sample *sample)
1922{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001923 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001924 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001925 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001926 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001927 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001928 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001929 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001930
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001931 if (sc == NULL)
1932 return -1;
1933
David Ahern8fb598e2013-09-28 13:13:00 -06001934 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001935 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001936 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001937 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001938
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001939 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001940
1941 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001942 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001943 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001944 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001945 }
1946
David Ahern13f22a2d2015-03-19 12:23:03 -06001947 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001948 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001949
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001950 ttrace->entry_time = sample->time;
1951 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001952 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001953
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001954 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001955 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001956
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001957 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001958 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001959 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1960 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001961 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001962 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001963 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001964 /* See trace__vfs_getname & trace__sys_exit */
1965 ttrace->filename.pending_open = false;
1966 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001967
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001968 if (trace->current != thread) {
1969 thread__put(trace->current);
1970 trace->current = thread__get(thread);
1971 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001972 err = 0;
1973out_put:
1974 thread__put(thread);
1975 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001976}
1977
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001978static int trace__fprintf_callchain(struct trace *trace, struct perf_evsel *evsel,
1979 struct perf_sample *sample)
1980{
1981 struct addr_location al;
1982 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001983 const unsigned int print_opts = EVSEL__PRINT_SYM |
1984 EVSEL__PRINT_DSO |
1985 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001986
1987 if (sample->callchain == NULL)
1988 return 0;
1989
1990 if (machine__resolve(trace->host, &al, sample) < 0) {
1991 pr_err("Problem processing %s callchain, skipping...\n",
1992 perf_evsel__name(evsel));
1993 return 0;
1994 }
1995
1996 return perf_evsel__fprintf_callchain(evsel, sample, &al, 38, print_opts,
1997 scripting_max_stack, trace->output);
1998}
1999
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002000static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002001 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002002 struct perf_sample *sample)
2003{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002004 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002005 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002006 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002007 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002008 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002009 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002010
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002011 if (sc == NULL)
2012 return -1;
2013
David Ahern8fb598e2013-09-28 13:13:00 -06002014 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002015 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002016 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002017 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002018
David Ahernbf2575c2013-10-08 21:26:53 -06002019 if (trace->summary)
2020 thread__update_stats(ttrace, id, sample);
2021
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002022 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002023
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002024 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002025 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
2026 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002027 ++trace->stats.vfs_getname;
2028 }
2029
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002030 ttrace->exit_time = sample->time;
2031
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002032 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002033 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002034 if (trace__filter_duration(trace, duration))
2035 goto out;
2036 } else if (trace->duration_filter)
2037 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002038
David Ahernfd2eaba2013-11-12 09:31:15 -07002039 if (trace->summary_only)
2040 goto out;
2041
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002042 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002043
2044 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002045 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002046 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002047 fprintf(trace->output, " ... [");
2048 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
2049 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002050 }
2051
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002052 if (sc->fmt == NULL) {
2053signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002054 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03002055 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00002056 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002057 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
2058 *e = audit_errno_to_name(-ret);
2059
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002060 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002061 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002062 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03002063 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002064 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03002065 else if (sc->fmt->errpid) {
2066 struct thread *child = machine__find_thread(trace->host, ret, ret);
2067
2068 if (child != NULL) {
2069 fprintf(trace->output, ") = %ld", ret);
2070 if (child->comm_set)
2071 fprintf(trace->output, " (%s)", thread__comm_str(child));
2072 thread__put(child);
2073 }
2074 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002075 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002076
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002077 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02002078
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03002079 trace__fprintf_callchain(trace, evsel, sample);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002080out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002081 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002082 err = 0;
2083out_put:
2084 thread__put(thread);
2085 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002086}
2087
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002088static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002089 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002090 struct perf_sample *sample)
2091{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002092 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2093 struct thread_trace *ttrace;
2094 size_t filename_len, entry_str_len, to_move;
2095 ssize_t remaining_space;
2096 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002097 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002098
2099 if (!thread)
2100 goto out;
2101
2102 ttrace = thread__priv(thread);
2103 if (!ttrace)
2104 goto out;
2105
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002106 filename_len = strlen(filename);
2107
2108 if (ttrace->filename.namelen < filename_len) {
2109 char *f = realloc(ttrace->filename.name, filename_len + 1);
2110
2111 if (f == NULL)
2112 goto out;
2113
2114 ttrace->filename.namelen = filename_len;
2115 ttrace->filename.name = f;
2116 }
2117
2118 strcpy(ttrace->filename.name, filename);
2119 ttrace->filename.pending_open = true;
2120
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002121 if (!ttrace->filename.ptr)
2122 goto out;
2123
2124 entry_str_len = strlen(ttrace->entry_str);
2125 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2126 if (remaining_space <= 0)
2127 goto out;
2128
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002129 if (filename_len > (size_t)remaining_space) {
2130 filename += filename_len - remaining_space;
2131 filename_len = remaining_space;
2132 }
2133
2134 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2135 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2136 memmove(pos + filename_len, pos, to_move);
2137 memcpy(pos, filename, filename_len);
2138
2139 ttrace->filename.ptr = 0;
2140 ttrace->filename.entry_str_pos = 0;
2141out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002142 return 0;
2143}
2144
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002145static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002146 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002147 struct perf_sample *sample)
2148{
2149 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2150 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06002151 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03002152 sample->pid,
2153 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002154 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002155
2156 if (ttrace == NULL)
2157 goto out_dump;
2158
2159 ttrace->runtime_ms += runtime_ms;
2160 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002161 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002162 return 0;
2163
2164out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002165 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002166 evsel->name,
2167 perf_evsel__strval(evsel, sample, "comm"),
2168 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2169 runtime,
2170 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002171 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002172 return 0;
2173}
2174
Wang Nan1d6c9402016-02-26 09:31:55 +00002175static void bpf_output__printer(enum binary_printer_ops op,
2176 unsigned int val, void *extra)
2177{
2178 FILE *output = extra;
2179 unsigned char ch = (unsigned char)val;
2180
2181 switch (op) {
2182 case BINARY_PRINT_CHAR_DATA:
2183 fprintf(output, "%c", isprint(ch) ? ch : '.');
2184 break;
2185 case BINARY_PRINT_DATA_BEGIN:
2186 case BINARY_PRINT_LINE_BEGIN:
2187 case BINARY_PRINT_ADDR:
2188 case BINARY_PRINT_NUM_DATA:
2189 case BINARY_PRINT_NUM_PAD:
2190 case BINARY_PRINT_SEP:
2191 case BINARY_PRINT_CHAR_PAD:
2192 case BINARY_PRINT_LINE_END:
2193 case BINARY_PRINT_DATA_END:
2194 default:
2195 break;
2196 }
2197}
2198
2199static void bpf_output__fprintf(struct trace *trace,
2200 struct perf_sample *sample)
2201{
2202 print_binary(sample->raw_data, sample->raw_size, 8,
2203 bpf_output__printer, trace->output);
2204}
2205
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002206static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2207 union perf_event *event __maybe_unused,
2208 struct perf_sample *sample)
2209{
2210 trace__printf_interrupted_entry(trace, sample);
2211 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002212
2213 if (trace->trace_syscalls)
2214 fprintf(trace->output, "( ): ");
2215
2216 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002217
Wang Nan1d6c9402016-02-26 09:31:55 +00002218 if (perf_evsel__is_bpf_output(evsel)) {
2219 bpf_output__fprintf(trace, sample);
2220 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002221 event_format__fprintf(evsel->tp_format, sample->cpu,
2222 sample->raw_data, sample->raw_size,
2223 trace->output);
2224 }
2225
2226 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03002227
2228 trace__fprintf_callchain(trace, evsel, sample);
2229
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002230 return 0;
2231}
2232
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002233static void print_location(FILE *f, struct perf_sample *sample,
2234 struct addr_location *al,
2235 bool print_dso, bool print_sym)
2236{
2237
2238 if ((verbose || print_dso) && al->map)
2239 fprintf(f, "%s@", al->map->dso->long_name);
2240
2241 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002242 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002243 al->addr - al->sym->start);
2244 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002245 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002246 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002247 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002248}
2249
2250static int trace__pgfault(struct trace *trace,
2251 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002252 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002253 struct perf_sample *sample)
2254{
2255 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002256 struct addr_location al;
2257 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002258 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002259 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002260
2261 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002262 ttrace = thread__trace(thread, trace->output);
2263 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002264 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002265
2266 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2267 ttrace->pfmaj++;
2268 else
2269 ttrace->pfmin++;
2270
2271 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002272 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002273
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002274 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002275 sample->ip, &al);
2276
2277 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2278
2279 fprintf(trace->output, "%sfault [",
2280 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2281 "maj" : "min");
2282
2283 print_location(trace->output, sample, &al, false, true);
2284
2285 fprintf(trace->output, "] => ");
2286
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002287 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002288 sample->addr, &al);
2289
2290 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002291 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002292 MAP__FUNCTION, sample->addr, &al);
2293
2294 if (al.map)
2295 map_type = 'x';
2296 else
2297 map_type = '?';
2298 }
2299
2300 print_location(trace->output, sample, &al, true, false);
2301
2302 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002303out:
2304 err = 0;
2305out_put:
2306 thread__put(thread);
2307 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002308}
2309
David Ahernbdc89662013-08-28 22:29:53 -06002310static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2311{
2312 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2313 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2314 return false;
2315
2316 if (trace->pid_list || trace->tid_list)
2317 return true;
2318
2319 return false;
2320}
2321
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002322static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002323 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002324 struct perf_sample *sample)
2325{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002326 /*
2327 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2328 * and don't use sample->time unconditionally, we may end up having
2329 * some other event in the future without PERF_SAMPLE_TIME for good
2330 * reason, i.e. we may not be interested in its timestamps, just in
2331 * it taking place, picking some piece of information when it
2332 * appears in our event stream (vfs_getname comes to mind).
2333 */
2334 if (trace->base_time == 0 && !trace->full_time &&
2335 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002336 trace->base_time = sample->time;
2337}
2338
David Ahern6810fc92013-08-28 22:29:52 -06002339static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002340 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002341 struct perf_sample *sample,
2342 struct perf_evsel *evsel,
2343 struct machine *machine __maybe_unused)
2344{
2345 struct trace *trace = container_of(tool, struct trace, tool);
2346 int err = 0;
2347
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002348 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002349
David Ahernbdc89662013-08-28 22:29:53 -06002350 if (skip_sample(trace, sample))
2351 return 0;
2352
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002353 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002354
David Ahern31605652013-12-04 19:41:41 -07002355 if (handler) {
2356 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002357 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002358 }
David Ahern6810fc92013-08-28 22:29:52 -06002359
2360 return err;
2361}
2362
David Ahernbdc89662013-08-28 22:29:53 -06002363static int parse_target_str(struct trace *trace)
2364{
2365 if (trace->opts.target.pid) {
2366 trace->pid_list = intlist__new(trace->opts.target.pid);
2367 if (trace->pid_list == NULL) {
2368 pr_err("Error parsing process id string\n");
2369 return -EINVAL;
2370 }
2371 }
2372
2373 if (trace->opts.target.tid) {
2374 trace->tid_list = intlist__new(trace->opts.target.tid);
2375 if (trace->tid_list == NULL) {
2376 pr_err("Error parsing thread id string\n");
2377 return -EINVAL;
2378 }
2379 }
2380
2381 return 0;
2382}
2383
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002384static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002385{
2386 unsigned int rec_argc, i, j;
2387 const char **rec_argv;
2388 const char * const record_args[] = {
2389 "record",
2390 "-R",
2391 "-m", "1024",
2392 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002393 };
2394
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002395 const char * const sc_args[] = { "-e", };
2396 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2397 const char * const majpf_args[] = { "-e", "major-faults" };
2398 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2399 const char * const minpf_args[] = { "-e", "minor-faults" };
2400 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2401
David Ahern9aca7f12013-12-04 19:41:39 -07002402 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002403 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2404 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002405 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2406
2407 if (rec_argv == NULL)
2408 return -ENOMEM;
2409
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002410 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002411 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002412 rec_argv[j++] = record_args[i];
2413
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002414 if (trace->trace_syscalls) {
2415 for (i = 0; i < sc_args_nr; i++)
2416 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002417
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002418 /* event string may be different for older kernels - e.g., RHEL6 */
2419 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2420 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2421 else if (is_valid_tracepoint("syscalls:sys_enter"))
2422 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2423 else {
2424 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2425 return -1;
2426 }
David Ahern9aca7f12013-12-04 19:41:39 -07002427 }
David Ahern9aca7f12013-12-04 19:41:39 -07002428
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002429 if (trace->trace_pgfaults & TRACE_PFMAJ)
2430 for (i = 0; i < majpf_args_nr; i++)
2431 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002432
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002433 if (trace->trace_pgfaults & TRACE_PFMIN)
2434 for (i = 0; i < minpf_args_nr; i++)
2435 rec_argv[j++] = minpf_args[i];
2436
2437 for (i = 0; i < (unsigned int)argc; i++)
2438 rec_argv[j++] = argv[i];
2439
2440 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002441}
2442
David Ahernbf2575c2013-10-08 21:26:53 -06002443static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2444
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002445static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002446{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002447 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002448
2449 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002450 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002451
2452 if (perf_evsel__field(evsel, "pathname") == NULL) {
2453 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002454 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002455 }
2456
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002457 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002458 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002459 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002460}
2461
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002462static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2463 u64 config)
2464{
2465 struct perf_evsel *evsel;
2466 struct perf_event_attr attr = {
2467 .type = PERF_TYPE_SOFTWARE,
2468 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002469 };
2470
2471 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002472 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002473
2474 event_attr_init(&attr);
2475
2476 evsel = perf_evsel__new(&attr);
2477 if (!evsel)
2478 return -ENOMEM;
2479
2480 evsel->handler = trace__pgfault;
2481 perf_evlist__add(evlist, evsel);
2482
2483 return 0;
2484}
2485
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002486static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2487{
2488 const u32 type = event->header.type;
2489 struct perf_evsel *evsel;
2490
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002491 if (type != PERF_RECORD_SAMPLE) {
2492 trace__process_event(trace, trace->host, event, sample);
2493 return;
2494 }
2495
2496 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2497 if (evsel == NULL) {
2498 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2499 return;
2500 }
2501
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002502 trace__set_base_time(trace, evsel, sample);
2503
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002504 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2505 sample->raw_data == NULL) {
2506 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2507 perf_evsel__name(evsel), sample->tid,
2508 sample->cpu, sample->raw_size);
2509 } else {
2510 tracepoint_handler handler = evsel->handler;
2511 handler(trace, evsel, event, sample);
2512 }
2513}
2514
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002515static int trace__add_syscall_newtp(struct trace *trace)
2516{
2517 int ret = -1;
2518 struct perf_evlist *evlist = trace->evlist;
2519 struct perf_evsel *sys_enter, *sys_exit;
2520
2521 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2522 if (sys_enter == NULL)
2523 goto out;
2524
2525 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2526 goto out_delete_sys_enter;
2527
2528 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2529 if (sys_exit == NULL)
2530 goto out_delete_sys_enter;
2531
2532 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2533 goto out_delete_sys_exit;
2534
2535 perf_evlist__add(evlist, sys_enter);
2536 perf_evlist__add(evlist, sys_exit);
2537
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002538 if (trace->opts.callgraph_set && !trace->kernel_syscallchains) {
2539 /*
2540 * We're interested only in the user space callchain
2541 * leading to the syscall, allow overriding that for
2542 * debugging reasons using --kernel_syscall_callchains
2543 */
2544 sys_exit->attr.exclude_callchain_kernel = 1;
2545 }
2546
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002547 trace->syscalls.events.sys_enter = sys_enter;
2548 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002549
2550 ret = 0;
2551out:
2552 return ret;
2553
2554out_delete_sys_exit:
2555 perf_evsel__delete_priv(sys_exit);
2556out_delete_sys_enter:
2557 perf_evsel__delete_priv(sys_enter);
2558 goto out;
2559}
2560
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002561static int trace__set_ev_qualifier_filter(struct trace *trace)
2562{
2563 int err = -1;
2564 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2565 trace->ev_qualifier_ids.nr,
2566 trace->ev_qualifier_ids.entries);
2567
2568 if (filter == NULL)
2569 goto out_enomem;
2570
2571 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2572 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2573
2574 free(filter);
2575out:
2576 return err;
2577out_enomem:
2578 errno = ENOMEM;
2579 goto out;
2580}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002581
Namhyung Kimf15eb532012-10-05 14:02:16 +09002582static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002583{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002584 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002585 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002586 int err = -1, i;
2587 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002588 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002589 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002590
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002591 trace->live = true;
2592
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002593 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002594 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002595
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002596 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002597 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002598
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002599 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002600 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002601 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002602 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002603
2604 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2605 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002606 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002607
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002608 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002609 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2610 trace__sched_stat_runtime))
2611 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002612
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002613 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2614 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002615 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002616 goto out_delete_evlist;
2617 }
2618
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002619 err = trace__symbols_init(trace, evlist);
2620 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002621 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002622 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002623 }
2624
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002625 perf_evlist__config(evlist, &trace->opts, NULL);
2626
2627 if (trace->opts.callgraph_set && trace->syscalls.events.sys_exit) {
2628 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2629 &trace->opts, &callchain_param);
2630 /*
2631 * Now we have evsels with different sample_ids, use
2632 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2633 * from a fixed position in each ring buffer record.
2634 *
2635 * As of this the changeset introducing this comment, this
2636 * isn't strictly needed, as the fields that can come before
2637 * PERF_SAMPLE_ID are all used, but we'll probably disable
2638 * some of those for things like copying the payload of
2639 * pointer syscall arguments, and for vfs_getname we don't
2640 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2641 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2642 */
2643 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2644 perf_evlist__reset_sample_bit(evlist, ID);
2645 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002646
Namhyung Kimf15eb532012-10-05 14:02:16 +09002647 signal(SIGCHLD, sig_handler);
2648 signal(SIGINT, sig_handler);
2649
2650 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002651 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002652 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002653 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002654 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002655 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002656 }
2657 }
2658
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002659 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002660 if (err < 0)
2661 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002662
Wang Nanba504232016-02-26 09:31:54 +00002663 err = bpf__apply_obj_config();
2664 if (err) {
2665 char errbuf[BUFSIZ];
2666
2667 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2668 pr_err("ERROR: Apply config to BPF failed: %s\n",
2669 errbuf);
2670 goto out_error_open;
2671 }
2672
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002673 /*
2674 * Better not use !target__has_task() here because we need to cover the
2675 * case where no threads were specified in the command line, but a
2676 * workload was, and in that case we will fill in the thread_map when
2677 * we fork the workload in perf_evlist__prepare_workload.
2678 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002679 if (trace->filter_pids.nr > 0)
2680 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002681 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002682 err = perf_evlist__set_filter_pid(evlist, getpid());
2683
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002684 if (err < 0)
2685 goto out_error_mem;
2686
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002687 if (trace->ev_qualifier_ids.nr > 0) {
2688 err = trace__set_ev_qualifier_filter(trace);
2689 if (err < 0)
2690 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002691
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002692 pr_debug("event qualifier tracepoint filter: %s\n",
2693 trace->syscalls.events.sys_exit->filter);
2694 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002695
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002696 err = perf_evlist__apply_filters(evlist, &evsel);
2697 if (err < 0)
2698 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002699
Jiri Olsaf8850372013-11-28 17:57:22 +01002700 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002701 if (err < 0)
2702 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002703
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002704 if (!target__none(&trace->opts.target))
2705 perf_evlist__enable(evlist);
2706
Namhyung Kimf15eb532012-10-05 14:02:16 +09002707 if (forks)
2708 perf_evlist__start_workload(evlist);
2709
Jiri Olsae13798c2015-06-23 00:36:02 +02002710 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002711 evlist->threads->nr > 1 ||
2712 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002713again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002714 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002715
2716 for (i = 0; i < evlist->nr_mmaps; i++) {
2717 union perf_event *event;
2718
2719 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002720 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002721
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002722 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002723
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002724 err = perf_evlist__parse_sample(evlist, event, &sample);
2725 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002726 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002727 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002728 }
2729
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002730 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002731next_event:
2732 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002733
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002734 if (interrupted)
2735 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002736
2737 if (done && !draining) {
2738 perf_evlist__disable(evlist);
2739 draining = true;
2740 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002741 }
2742 }
2743
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002744 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002745 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002746
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002747 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2748 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2749 draining = true;
2750
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002751 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002752 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002753 } else {
2754 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002755 }
2756
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002757out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002758 thread__zput(trace->current);
2759
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002760 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002761
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002762 if (!err) {
2763 if (trace->summary)
2764 trace__fprintf_thread_summary(trace, trace->output);
2765
2766 if (trace->show_tool_stats) {
2767 fprintf(trace->output, "Stats:\n "
2768 " vfs_getname : %" PRIu64 "\n"
2769 " proc_getname: %" PRIu64 "\n",
2770 trace->stats.vfs_getname,
2771 trace->stats.proc_getname);
2772 }
2773 }
David Ahernbf2575c2013-10-08 21:26:53 -06002774
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002775out_delete_evlist:
2776 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002777 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002778 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002779 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002780{
2781 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002782
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002783out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002784 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002785 goto out_error;
2786
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002787out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002788 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002789 goto out_error;
2790
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002791out_error_mmap:
2792 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2793 goto out_error;
2794
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002795out_error_open:
2796 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2797
2798out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002799 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302800 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002801
2802out_error_apply_filters:
2803 fprintf(trace->output,
2804 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2805 evsel->filter, perf_evsel__name(evsel), errno,
2806 strerror_r(errno, errbuf, sizeof(errbuf)));
2807 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002808}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002809out_error_mem:
2810 fprintf(trace->output, "Not enough memory to run!\n");
2811 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002812
2813out_errno:
2814 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2815 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002816}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002817
David Ahern6810fc92013-08-28 22:29:52 -06002818static int trace__replay(struct trace *trace)
2819{
2820 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002821 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002822 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002823 struct perf_data_file file = {
2824 .path = input_name,
2825 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002826 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002827 };
David Ahern6810fc92013-08-28 22:29:52 -06002828 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002829 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002830 int err = -1;
2831
2832 trace->tool.sample = trace__process_sample;
2833 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002834 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002835 trace->tool.comm = perf_event__process_comm;
2836 trace->tool.exit = perf_event__process_exit;
2837 trace->tool.fork = perf_event__process_fork;
2838 trace->tool.attr = perf_event__process_attr;
2839 trace->tool.tracing_data = perf_event__process_tracing_data;
2840 trace->tool.build_id = perf_event__process_build_id;
2841
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002842 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002843 trace->tool.ordering_requires_timestamps = true;
2844
2845 /* add tid to output */
2846 trace->multiple_threads = true;
2847
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002848 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002849 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002850 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002851
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002852 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002853 goto out;
2854
David Ahern8fb598e2013-09-28 13:13:00 -06002855 trace->host = &session->machines.host;
2856
David Ahern6810fc92013-08-28 22:29:52 -06002857 err = perf_session__set_tracepoints_handlers(session, handlers);
2858 if (err)
2859 goto out;
2860
Namhyung Kim003824e2013-11-12 15:25:00 +09002861 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2862 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002863 /* older kernels have syscalls tp versus raw_syscalls */
2864 if (evsel == NULL)
2865 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2866 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002867
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002868 if (evsel &&
2869 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2870 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002871 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2872 goto out;
2873 }
2874
2875 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2876 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002877 if (evsel == NULL)
2878 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2879 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002880 if (evsel &&
2881 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2882 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002883 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002884 goto out;
2885 }
2886
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002887 evlist__for_each(session->evlist, evsel) {
2888 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2889 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2890 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2891 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2892 evsel->handler = trace__pgfault;
2893 }
2894
David Ahernbdc89662013-08-28 22:29:53 -06002895 err = parse_target_str(trace);
2896 if (err != 0)
2897 goto out;
2898
David Ahern6810fc92013-08-28 22:29:52 -06002899 setup_pager();
2900
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002901 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002902 if (err)
2903 pr_err("Failed to process events, error %d", err);
2904
David Ahernbf2575c2013-10-08 21:26:53 -06002905 else if (trace->summary)
2906 trace__fprintf_thread_summary(trace, trace->output);
2907
David Ahern6810fc92013-08-28 22:29:52 -06002908out:
2909 perf_session__delete(session);
2910
2911 return err;
2912}
2913
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002914static size_t trace__fprintf_threads_header(FILE *fp)
2915{
2916 size_t printed;
2917
Pekka Enberg99ff7152013-11-12 16:42:14 +02002918 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002919
2920 return printed;
2921}
2922
2923static size_t thread__dump_stats(struct thread_trace *ttrace,
2924 struct trace *trace, FILE *fp)
2925{
2926 struct stats *stats;
2927 size_t printed = 0;
2928 struct syscall *sc;
2929 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2930
2931 if (inode == NULL)
2932 return 0;
2933
2934 printed += fprintf(fp, "\n");
2935
Milian Wolff834fd462015-08-06 11:24:29 +02002936 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2937 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2938 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002939
David Ahernbf2575c2013-10-08 21:26:53 -06002940 /* each int_node is a syscall */
2941 while (inode) {
2942 stats = inode->priv;
2943 if (stats) {
2944 double min = (double)(stats->min) / NSEC_PER_MSEC;
2945 double max = (double)(stats->max) / NSEC_PER_MSEC;
2946 double avg = avg_stats(stats);
2947 double pct;
2948 u64 n = (u64) stats->n;
2949
2950 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2951 avg /= NSEC_PER_MSEC;
2952
2953 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002954 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002955 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
2956 n, avg * n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002957 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002958 }
2959
2960 inode = intlist__next(inode);
2961 }
2962
2963 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002964
2965 return printed;
2966}
2967
David Ahern896cbb52013-09-28 13:12:59 -06002968/* struct used to pass data to per-thread function */
2969struct summary_data {
2970 FILE *fp;
2971 struct trace *trace;
2972 size_t printed;
2973};
2974
2975static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2976{
2977 struct summary_data *data = priv;
2978 FILE *fp = data->fp;
2979 size_t printed = data->printed;
2980 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002981 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002982 double ratio;
2983
2984 if (ttrace == NULL)
2985 return 0;
2986
2987 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2988
Pekka Enberg15e65c62013-11-14 18:43:30 +02002989 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002990 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002991 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002992 if (ttrace->pfmaj)
2993 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2994 if (ttrace->pfmin)
2995 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002996 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002997 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002998
2999 data->printed += printed;
3000
3001 return 0;
3002}
3003
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003004static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
3005{
David Ahern896cbb52013-09-28 13:12:59 -06003006 struct summary_data data = {
3007 .fp = fp,
3008 .trace = trace
3009 };
3010 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003011
David Ahern896cbb52013-09-28 13:12:59 -06003012 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003013
David Ahern896cbb52013-09-28 13:12:59 -06003014 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003015}
3016
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003017static int trace__set_duration(const struct option *opt, const char *str,
3018 int unset __maybe_unused)
3019{
3020 struct trace *trace = opt->value;
3021
3022 trace->duration_filter = atof(str);
3023 return 0;
3024}
3025
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08003026static int trace__set_filter_pids(const struct option *opt, const char *str,
3027 int unset __maybe_unused)
3028{
3029 int ret = -1;
3030 size_t i;
3031 struct trace *trace = opt->value;
3032 /*
3033 * FIXME: introduce a intarray class, plain parse csv and create a
3034 * { int nr, int entries[] } struct...
3035 */
3036 struct intlist *list = intlist__new(str);
3037
3038 if (list == NULL)
3039 return -1;
3040
3041 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
3042 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
3043
3044 if (trace->filter_pids.entries == NULL)
3045 goto out;
3046
3047 trace->filter_pids.entries[0] = getpid();
3048
3049 for (i = 1; i < trace->filter_pids.nr; ++i)
3050 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
3051
3052 intlist__delete(list);
3053 ret = 0;
3054out:
3055 return ret;
3056}
3057
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003058static int trace__open_output(struct trace *trace, const char *filename)
3059{
3060 struct stat st;
3061
3062 if (!stat(filename, &st) && st.st_size) {
3063 char oldname[PATH_MAX];
3064
3065 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
3066 unlink(oldname);
3067 rename(filename, oldname);
3068 }
3069
3070 trace->output = fopen(filename, "w");
3071
3072 return trace->output == NULL ? -errno : 0;
3073}
3074
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003075static int parse_pagefaults(const struct option *opt, const char *str,
3076 int unset __maybe_unused)
3077{
3078 int *trace_pgfaults = opt->value;
3079
3080 if (strcmp(str, "all") == 0)
3081 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
3082 else if (strcmp(str, "maj") == 0)
3083 *trace_pgfaults |= TRACE_PFMAJ;
3084 else if (strcmp(str, "min") == 0)
3085 *trace_pgfaults |= TRACE_PFMIN;
3086 else
3087 return -1;
3088
3089 return 0;
3090}
3091
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003092static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3093{
3094 struct perf_evsel *evsel;
3095
3096 evlist__for_each(evlist, evsel)
3097 evsel->handler = handler;
3098}
3099
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003100int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3101{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003102 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003103 "perf trace [<options>] [<command>]",
3104 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003105 "perf trace record [<options>] [<command>]",
3106 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003107 NULL
3108 };
3109 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003110 .syscalls = {
3111 . max = -1,
3112 },
3113 .opts = {
3114 .target = {
3115 .uid = UINT_MAX,
3116 .uses_mmap = true,
3117 },
3118 .user_freq = UINT_MAX,
3119 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003120 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003121 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003122 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003123 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003124 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003125 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003126 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003127 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003128 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003129 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003130 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003131 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003132 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3133 "event selector. use 'perf list' to list available events",
3134 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003135 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3136 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003137 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03003138 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003139 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003140 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003141 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3142 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003143 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003144 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003145 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3146 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003147 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003148 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003149 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003150 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003151 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003152 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003153 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3154 "number of mmap data pages",
3155 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003156 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003157 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003158 OPT_CALLBACK(0, "duration", &trace, "float",
3159 "show only events with duration > N.M ms",
3160 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003161 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003162 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003163 OPT_BOOLEAN('T', "time", &trace.full_time,
3164 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003165 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3166 "Show only syscall summary with statistics"),
3167 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3168 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003169 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3170 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003171 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003172 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003173 OPT_CALLBACK(0, "call-graph", &trace.opts,
3174 "record_mode[,record_size]", record_callchain_help,
3175 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003176 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3177 "Show the kernel callchains on the syscall exit path"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003178 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3179 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003180 OPT_END()
3181 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003182 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003183 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003184 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003185
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003186 signal(SIGSEGV, sighandler_dump_stack);
3187 signal(SIGFPE, sighandler_dump_stack);
3188
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003189 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003190 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003191
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003192 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003193 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003194 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003195 goto out;
3196 }
3197
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003198 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3199 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003200
Wang Nand7888572016-04-08 15:07:24 +00003201 err = bpf__setup_stdout(trace.evlist);
3202 if (err) {
3203 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3204 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3205 goto out;
3206 }
3207
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003208 err = -1;
3209
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003210 if (trace.trace_pgfaults) {
3211 trace.opts.sample_address = true;
3212 trace.opts.sample_time = true;
3213 }
3214
Milian Wolff566a0882016-04-08 13:34:15 +02003215 if (trace.opts.callgraph_set)
3216 symbol_conf.use_callchain = true;
3217
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003218 if (trace.evlist->nr_entries > 0)
3219 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3220
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003221 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3222 return trace__record(&trace, argc-1, &argv[1]);
3223
3224 /* summary_only implies summary option, but don't overwrite summary if set */
3225 if (trace.summary_only)
3226 trace.summary = trace.summary_only;
3227
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003228 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3229 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003230 pr_err("Please specify something to trace.\n");
3231 return -1;
3232 }
3233
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003234 if (!trace.trace_syscalls && ev_qualifier_str) {
3235 pr_err("The -e option can't be used with --no-syscalls.\n");
3236 goto out;
3237 }
3238
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003239 if (output_name != NULL) {
3240 err = trace__open_output(&trace, output_name);
3241 if (err < 0) {
3242 perror("failed to create output file");
3243 goto out;
3244 }
3245 }
3246
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003247 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3248
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003249 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003250 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03003251 struct strlist_config slist_config = {
3252 .dirname = system_path(STRACE_GROUPS_DIR),
3253 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003254
3255 trace.not_ev_qualifier = *s == '!';
3256 if (trace.not_ev_qualifier)
3257 ++s;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03003258 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003259 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003260 fputs("Not enough memory to parse event qualifier",
3261 trace.output);
3262 err = -ENOMEM;
3263 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003264 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003265
3266 err = trace__validate_ev_qualifier(&trace);
3267 if (err)
3268 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003269 }
3270
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003271 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003272 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003273 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003274 fprintf(trace.output, "%s", bf);
3275 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003276 }
3277
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003278 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003279 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003280 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003281 fprintf(trace.output, "%s", bf);
3282 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003283 }
3284
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003285 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003286 trace.opts.target.system_wide = true;
3287
David Ahern6810fc92013-08-28 22:29:52 -06003288 if (input_name)
3289 err = trace__replay(&trace);
3290 else
3291 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003292
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003293out_close:
3294 if (output_name != NULL)
3295 fclose(trace.output);
3296out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003297 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003298}