blob: 246866c63e5ec5b8887d1b49f168e37fd6ec894d [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 Meloae685382013-08-20 17:44:42 -030042#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030043#include <linux/futex.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020044#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030045#include <linux/seccomp.h>
46#include <linux/filter.h>
47#include <linux/audit.h>
48#include <sys/ptrace.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030049#include <linux/random.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030050
Ingo Molnar456857b2013-09-12 15:29:00 +020051/* For older distros: */
52#ifndef MAP_STACK
53# define MAP_STACK 0x20000
54#endif
55
56#ifndef MADV_HWPOISON
57# define MADV_HWPOISON 100
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -030058
Ingo Molnar456857b2013-09-12 15:29:00 +020059#endif
60
61#ifndef MADV_MERGEABLE
62# define MADV_MERGEABLE 12
63#endif
64
65#ifndef MADV_UNMERGEABLE
66# define MADV_UNMERGEABLE 13
67#endif
68
Ben Hutchings79d26a62014-02-06 01:00:35 +000069#ifndef EFD_SEMAPHORE
70# define EFD_SEMAPHORE 1
71#endif
72
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030073#ifndef EFD_NONBLOCK
74# define EFD_NONBLOCK 00004000
75#endif
76
77#ifndef EFD_CLOEXEC
78# define EFD_CLOEXEC 02000000
79#endif
80
81#ifndef O_CLOEXEC
82# define O_CLOEXEC 02000000
83#endif
84
85#ifndef SOCK_DCCP
86# define SOCK_DCCP 6
87#endif
88
89#ifndef SOCK_CLOEXEC
90# define SOCK_CLOEXEC 02000000
91#endif
92
93#ifndef SOCK_NONBLOCK
94# define SOCK_NONBLOCK 00004000
95#endif
96
97#ifndef MSG_CMSG_CLOEXEC
98# define MSG_CMSG_CLOEXEC 0x40000000
99#endif
100
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300101#ifndef PERF_FLAG_FD_NO_GROUP
102# define PERF_FLAG_FD_NO_GROUP (1UL << 0)
103#endif
104
105#ifndef PERF_FLAG_FD_OUTPUT
106# define PERF_FLAG_FD_OUTPUT (1UL << 1)
107#endif
108
109#ifndef PERF_FLAG_PID_CGROUP
110# define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */
111#endif
112
113#ifndef PERF_FLAG_FD_CLOEXEC
114# define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */
115#endif
116
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300117struct trace {
118 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300119 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300120 struct {
121 int max;
122 struct syscall *table;
123 struct {
124 struct perf_evsel *sys_enter,
125 *sys_exit;
126 } events;
127 } syscalls;
128 struct record_opts opts;
129 struct perf_evlist *evlist;
130 struct machine *host;
131 struct thread *current;
132 u64 base_time;
133 FILE *output;
134 unsigned long nr_events;
135 struct strlist *ev_qualifier;
136 struct {
137 size_t nr;
138 int *entries;
139 } ev_qualifier_ids;
140 struct intlist *tid_list;
141 struct intlist *pid_list;
142 struct {
143 size_t nr;
144 pid_t *entries;
145 } filter_pids;
146 double duration_filter;
147 double runtime_ms;
148 struct {
149 u64 vfs_getname,
150 proc_getname;
151 } stats;
152 bool not_ev_qualifier;
153 bool live;
154 bool full_time;
155 bool sched;
156 bool multiple_threads;
157 bool summary;
158 bool summary_only;
159 bool show_comm;
160 bool show_tool_stats;
161 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300162 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300163 bool force;
164 bool vfs_getname;
165 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300166 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300167};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300168
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300169struct tp_field {
170 int offset;
171 union {
172 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
173 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
174 };
175};
176
177#define TP_UINT_FIELD(bits) \
178static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
179{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500180 u##bits value; \
181 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
182 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300183}
184
185TP_UINT_FIELD(8);
186TP_UINT_FIELD(16);
187TP_UINT_FIELD(32);
188TP_UINT_FIELD(64);
189
190#define TP_UINT_FIELD__SWAPPED(bits) \
191static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
192{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500193 u##bits value; \
194 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300195 return bswap_##bits(value);\
196}
197
198TP_UINT_FIELD__SWAPPED(16);
199TP_UINT_FIELD__SWAPPED(32);
200TP_UINT_FIELD__SWAPPED(64);
201
202static int tp_field__init_uint(struct tp_field *field,
203 struct format_field *format_field,
204 bool needs_swap)
205{
206 field->offset = format_field->offset;
207
208 switch (format_field->size) {
209 case 1:
210 field->integer = tp_field__u8;
211 break;
212 case 2:
213 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
214 break;
215 case 4:
216 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
217 break;
218 case 8:
219 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
220 break;
221 default:
222 return -1;
223 }
224
225 return 0;
226}
227
228static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
229{
230 return sample->raw_data + field->offset;
231}
232
233static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
234{
235 field->offset = format_field->offset;
236 field->pointer = tp_field__ptr;
237 return 0;
238}
239
240struct syscall_tp {
241 struct tp_field id;
242 union {
243 struct tp_field args, ret;
244 };
245};
246
247static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
248 struct tp_field *field,
249 const char *name)
250{
251 struct format_field *format_field = perf_evsel__field(evsel, name);
252
253 if (format_field == NULL)
254 return -1;
255
256 return tp_field__init_uint(field, format_field, evsel->needs_swap);
257}
258
259#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
260 ({ struct syscall_tp *sc = evsel->priv;\
261 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
262
263static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
264 struct tp_field *field,
265 const char *name)
266{
267 struct format_field *format_field = perf_evsel__field(evsel, name);
268
269 if (format_field == NULL)
270 return -1;
271
272 return tp_field__init_ptr(field, format_field);
273}
274
275#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
276 ({ struct syscall_tp *sc = evsel->priv;\
277 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
278
279static void perf_evsel__delete_priv(struct perf_evsel *evsel)
280{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300281 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300282 perf_evsel__delete(evsel);
283}
284
Namhyung Kim96695d42013-11-12 08:51:45 -0300285static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
286{
287 evsel->priv = malloc(sizeof(struct syscall_tp));
288 if (evsel->priv != NULL) {
289 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
290 goto out_delete;
291
292 evsel->handler = handler;
293 return 0;
294 }
295
296 return -ENOMEM;
297
298out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300299 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300300 return -ENOENT;
301}
302
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300303static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300304{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300305 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300306
David Ahern9aca7f12013-12-04 19:41:39 -0700307 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200308 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700309 evsel = perf_evsel__newtp("syscalls", direction);
310
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200311 if (IS_ERR(evsel))
312 return NULL;
313
314 if (perf_evsel__init_syscall_tp(evsel, handler))
315 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300316
317 return evsel;
318
319out_delete:
320 perf_evsel__delete_priv(evsel);
321 return NULL;
322}
323
324#define perf_evsel__sc_tp_uint(evsel, name, sample) \
325 ({ struct syscall_tp *fields = evsel->priv; \
326 fields->name.integer(&fields->name, sample); })
327
328#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
329 ({ struct syscall_tp *fields = evsel->priv; \
330 fields->name.pointer(&fields->name, sample); })
331
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300332struct syscall_arg {
333 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300334 struct thread *thread;
335 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300336 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300337 u8 idx;
338 u8 mask;
339};
340
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300341struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300342 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300343 int nr_entries;
344 const char **entries;
345};
346
347#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
348 .nr_entries = ARRAY_SIZE(array), \
349 .entries = array, \
350}
351
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300352#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
353 .offset = off, \
354 .nr_entries = ARRAY_SIZE(array), \
355 .entries = array, \
356}
357
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300358static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
359 const char *intfmt,
360 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300361{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300362 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300363 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300364
365 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300366 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300367
368 return scnprintf(bf, size, "%s", sa->entries[idx]);
369}
370
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300371static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
372 struct syscall_arg *arg)
373{
374 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
375}
376
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300377#define SCA_STRARRAY syscall_arg__scnprintf_strarray
378
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300379#if defined(__i386__) || defined(__x86_64__)
380/*
381 * FIXME: Make this available to all arches as soon as the ioctl beautifier
382 * gets rewritten to support all arches.
383 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300384static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
385 struct syscall_arg *arg)
386{
387 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
388}
389
390#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300391#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300392
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300393static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
394 struct syscall_arg *arg);
395
396#define SCA_FD syscall_arg__scnprintf_fd
397
398static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
399 struct syscall_arg *arg)
400{
401 int fd = arg->val;
402
403 if (fd == AT_FDCWD)
404 return scnprintf(bf, size, "CWD");
405
406 return syscall_arg__scnprintf_fd(bf, size, arg);
407}
408
409#define SCA_FDAT syscall_arg__scnprintf_fd_at
410
411static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
412 struct syscall_arg *arg);
413
414#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
415
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300416static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300417 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300418{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300419 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300420}
421
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300422#define SCA_HEX syscall_arg__scnprintf_hex
423
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300424static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
425 struct syscall_arg *arg)
426{
427 return scnprintf(bf, size, "%d", arg->val);
428}
429
430#define SCA_INT syscall_arg__scnprintf_int
431
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300432static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300433 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300434{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300435 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300436
437 if (prot == PROT_NONE)
438 return scnprintf(bf, size, "NONE");
439#define P_MMAP_PROT(n) \
440 if (prot & PROT_##n) { \
441 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
442 prot &= ~PROT_##n; \
443 }
444
445 P_MMAP_PROT(EXEC);
446 P_MMAP_PROT(READ);
447 P_MMAP_PROT(WRITE);
448#ifdef PROT_SEM
449 P_MMAP_PROT(SEM);
450#endif
451 P_MMAP_PROT(GROWSDOWN);
452 P_MMAP_PROT(GROWSUP);
453#undef P_MMAP_PROT
454
455 if (prot)
456 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
457
458 return printed;
459}
460
461#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
462
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300463static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300464 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300465{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300466 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300467
468#define P_MMAP_FLAG(n) \
469 if (flags & MAP_##n) { \
470 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
471 flags &= ~MAP_##n; \
472 }
473
474 P_MMAP_FLAG(SHARED);
475 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400476#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300477 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400478#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300479 P_MMAP_FLAG(ANONYMOUS);
480 P_MMAP_FLAG(DENYWRITE);
481 P_MMAP_FLAG(EXECUTABLE);
482 P_MMAP_FLAG(FILE);
483 P_MMAP_FLAG(FIXED);
484 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600485#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300486 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600487#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300488 P_MMAP_FLAG(LOCKED);
489 P_MMAP_FLAG(NONBLOCK);
490 P_MMAP_FLAG(NORESERVE);
491 P_MMAP_FLAG(POPULATE);
492 P_MMAP_FLAG(STACK);
493#ifdef MAP_UNINITIALIZED
494 P_MMAP_FLAG(UNINITIALIZED);
495#endif
496#undef P_MMAP_FLAG
497
498 if (flags)
499 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
500
501 return printed;
502}
503
504#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
505
Alex Snast86998dd2014-08-13 18:42:40 +0300506static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
507 struct syscall_arg *arg)
508{
509 int printed = 0, flags = arg->val;
510
511#define P_MREMAP_FLAG(n) \
512 if (flags & MREMAP_##n) { \
513 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
514 flags &= ~MREMAP_##n; \
515 }
516
517 P_MREMAP_FLAG(MAYMOVE);
518#ifdef MREMAP_FIXED
519 P_MREMAP_FLAG(FIXED);
520#endif
521#undef P_MREMAP_FLAG
522
523 if (flags)
524 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
525
526 return printed;
527}
528
529#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
530
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300531static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300532 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300533{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300534 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300535
536 switch (behavior) {
537#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
538 P_MADV_BHV(NORMAL);
539 P_MADV_BHV(RANDOM);
540 P_MADV_BHV(SEQUENTIAL);
541 P_MADV_BHV(WILLNEED);
542 P_MADV_BHV(DONTNEED);
543 P_MADV_BHV(REMOVE);
544 P_MADV_BHV(DONTFORK);
545 P_MADV_BHV(DOFORK);
546 P_MADV_BHV(HWPOISON);
547#ifdef MADV_SOFT_OFFLINE
548 P_MADV_BHV(SOFT_OFFLINE);
549#endif
550 P_MADV_BHV(MERGEABLE);
551 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600552#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300553 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600554#endif
555#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300556 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600557#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300558#ifdef MADV_DONTDUMP
559 P_MADV_BHV(DONTDUMP);
560#endif
561#ifdef MADV_DODUMP
562 P_MADV_BHV(DODUMP);
563#endif
564#undef P_MADV_PHV
565 default: break;
566 }
567
568 return scnprintf(bf, size, "%#x", behavior);
569}
570
571#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
572
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300573static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
574 struct syscall_arg *arg)
575{
576 int printed = 0, op = arg->val;
577
578 if (op == 0)
579 return scnprintf(bf, size, "NONE");
580#define P_CMD(cmd) \
581 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
582 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
583 op &= ~LOCK_##cmd; \
584 }
585
586 P_CMD(SH);
587 P_CMD(EX);
588 P_CMD(NB);
589 P_CMD(UN);
590 P_CMD(MAND);
591 P_CMD(RW);
592 P_CMD(READ);
593 P_CMD(WRITE);
594#undef P_OP
595
596 if (op)
597 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
598
599 return printed;
600}
601
602#define SCA_FLOCK syscall_arg__scnprintf_flock
603
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300604static 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 -0300605{
606 enum syscall_futex_args {
607 SCF_UADDR = (1 << 0),
608 SCF_OP = (1 << 1),
609 SCF_VAL = (1 << 2),
610 SCF_TIMEOUT = (1 << 3),
611 SCF_UADDR2 = (1 << 4),
612 SCF_VAL3 = (1 << 5),
613 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300614 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300615 int cmd = op & FUTEX_CMD_MASK;
616 size_t printed = 0;
617
618 switch (cmd) {
619#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300620 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
621 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
622 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
623 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
624 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
625 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300626 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300627 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
628 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
629 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
630 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
631 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300632 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
633 default: printed = scnprintf(bf, size, "%#x", cmd); break;
634 }
635
636 if (op & FUTEX_PRIVATE_FLAG)
637 printed += scnprintf(bf + printed, size - printed, "|PRIV");
638
639 if (op & FUTEX_CLOCK_REALTIME)
640 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
641
642 return printed;
643}
644
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300645#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
646
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300647static const char *bpf_cmd[] = {
648 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
649 "MAP_GET_NEXT_KEY", "PROG_LOAD",
650};
651static DEFINE_STRARRAY(bpf_cmd);
652
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300653static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
654static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300655
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300656static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
657static DEFINE_STRARRAY(itimers);
658
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300659static const char *keyctl_options[] = {
660 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
661 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
662 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
663 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
664 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
665};
666static DEFINE_STRARRAY(keyctl_options);
667
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300668static const char *whences[] = { "SET", "CUR", "END",
669#ifdef SEEK_DATA
670"DATA",
671#endif
672#ifdef SEEK_HOLE
673"HOLE",
674#endif
675};
676static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300677
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300678static const char *fcntl_cmds[] = {
679 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
680 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
681 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
682 "F_GETOWNER_UIDS",
683};
684static DEFINE_STRARRAY(fcntl_cmds);
685
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300686static const char *rlimit_resources[] = {
687 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
688 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
689 "RTTIME",
690};
691static DEFINE_STRARRAY(rlimit_resources);
692
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300693static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
694static DEFINE_STRARRAY(sighow);
695
David Ahern4f8c1b72013-09-22 19:45:00 -0600696static const char *clockid[] = {
697 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300698 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
699 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600700};
701static DEFINE_STRARRAY(clockid);
702
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300703static const char *socket_families[] = {
704 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
705 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
706 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
707 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
708 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
709 "ALG", "NFC", "VSOCK",
710};
711static DEFINE_STRARRAY(socket_families);
712
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300713#ifndef SOCK_TYPE_MASK
714#define SOCK_TYPE_MASK 0xf
715#endif
716
717static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
718 struct syscall_arg *arg)
719{
720 size_t printed;
721 int type = arg->val,
722 flags = type & ~SOCK_TYPE_MASK;
723
724 type &= SOCK_TYPE_MASK;
725 /*
726 * Can't use a strarray, MIPS may override for ABI reasons.
727 */
728 switch (type) {
729#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
730 P_SK_TYPE(STREAM);
731 P_SK_TYPE(DGRAM);
732 P_SK_TYPE(RAW);
733 P_SK_TYPE(RDM);
734 P_SK_TYPE(SEQPACKET);
735 P_SK_TYPE(DCCP);
736 P_SK_TYPE(PACKET);
737#undef P_SK_TYPE
738 default:
739 printed = scnprintf(bf, size, "%#x", type);
740 }
741
742#define P_SK_FLAG(n) \
743 if (flags & SOCK_##n) { \
744 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
745 flags &= ~SOCK_##n; \
746 }
747
748 P_SK_FLAG(CLOEXEC);
749 P_SK_FLAG(NONBLOCK);
750#undef P_SK_FLAG
751
752 if (flags)
753 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
754
755 return printed;
756}
757
758#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
759
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300760#ifndef MSG_PROBE
761#define MSG_PROBE 0x10
762#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600763#ifndef MSG_WAITFORONE
764#define MSG_WAITFORONE 0x10000
765#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300766#ifndef MSG_SENDPAGE_NOTLAST
767#define MSG_SENDPAGE_NOTLAST 0x20000
768#endif
769#ifndef MSG_FASTOPEN
770#define MSG_FASTOPEN 0x20000000
771#endif
772
773static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
774 struct syscall_arg *arg)
775{
776 int printed = 0, flags = arg->val;
777
778 if (flags == 0)
779 return scnprintf(bf, size, "NONE");
780#define P_MSG_FLAG(n) \
781 if (flags & MSG_##n) { \
782 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
783 flags &= ~MSG_##n; \
784 }
785
786 P_MSG_FLAG(OOB);
787 P_MSG_FLAG(PEEK);
788 P_MSG_FLAG(DONTROUTE);
789 P_MSG_FLAG(TRYHARD);
790 P_MSG_FLAG(CTRUNC);
791 P_MSG_FLAG(PROBE);
792 P_MSG_FLAG(TRUNC);
793 P_MSG_FLAG(DONTWAIT);
794 P_MSG_FLAG(EOR);
795 P_MSG_FLAG(WAITALL);
796 P_MSG_FLAG(FIN);
797 P_MSG_FLAG(SYN);
798 P_MSG_FLAG(CONFIRM);
799 P_MSG_FLAG(RST);
800 P_MSG_FLAG(ERRQUEUE);
801 P_MSG_FLAG(NOSIGNAL);
802 P_MSG_FLAG(MORE);
803 P_MSG_FLAG(WAITFORONE);
804 P_MSG_FLAG(SENDPAGE_NOTLAST);
805 P_MSG_FLAG(FASTOPEN);
806 P_MSG_FLAG(CMSG_CLOEXEC);
807#undef P_MSG_FLAG
808
809 if (flags)
810 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
811
812 return printed;
813}
814
815#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
816
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300817static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
818 struct syscall_arg *arg)
819{
820 size_t printed = 0;
821 int mode = arg->val;
822
823 if (mode == F_OK) /* 0 */
824 return scnprintf(bf, size, "F");
825#define P_MODE(n) \
826 if (mode & n##_OK) { \
827 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
828 mode &= ~n##_OK; \
829 }
830
831 P_MODE(R);
832 P_MODE(W);
833 P_MODE(X);
834#undef P_MODE
835
836 if (mode)
837 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
838
839 return printed;
840}
841
842#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
843
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300844static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
845 struct syscall_arg *arg);
846
847#define SCA_FILENAME syscall_arg__scnprintf_filename
848
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300849static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300850 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300851{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300852 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300853
854 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300855 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300856
857 if (flags == 0)
858 return scnprintf(bf, size, "RDONLY");
859#define P_FLAG(n) \
860 if (flags & O_##n) { \
861 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
862 flags &= ~O_##n; \
863 }
864
865 P_FLAG(APPEND);
866 P_FLAG(ASYNC);
867 P_FLAG(CLOEXEC);
868 P_FLAG(CREAT);
869 P_FLAG(DIRECT);
870 P_FLAG(DIRECTORY);
871 P_FLAG(EXCL);
872 P_FLAG(LARGEFILE);
873 P_FLAG(NOATIME);
874 P_FLAG(NOCTTY);
875#ifdef O_NONBLOCK
876 P_FLAG(NONBLOCK);
877#elif O_NDELAY
878 P_FLAG(NDELAY);
879#endif
880#ifdef O_PATH
881 P_FLAG(PATH);
882#endif
883 P_FLAG(RDWR);
884#ifdef O_DSYNC
885 if ((flags & O_SYNC) == O_SYNC)
886 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
887 else {
888 P_FLAG(DSYNC);
889 }
890#else
891 P_FLAG(SYNC);
892#endif
893 P_FLAG(TRUNC);
894 P_FLAG(WRONLY);
895#undef P_FLAG
896
897 if (flags)
898 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
899
900 return printed;
901}
902
903#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
904
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300905static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size,
906 struct syscall_arg *arg)
907{
908 int printed = 0, flags = arg->val;
909
910 if (flags == 0)
911 return 0;
912
913#define P_FLAG(n) \
914 if (flags & PERF_FLAG_##n) { \
915 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
916 flags &= ~PERF_FLAG_##n; \
917 }
918
919 P_FLAG(FD_NO_GROUP);
920 P_FLAG(FD_OUTPUT);
921 P_FLAG(PID_CGROUP);
922 P_FLAG(FD_CLOEXEC);
923#undef P_FLAG
924
925 if (flags)
926 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
927
928 return printed;
929}
930
931#define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags
932
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300933static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
934 struct syscall_arg *arg)
935{
936 int printed = 0, flags = arg->val;
937
938 if (flags == 0)
939 return scnprintf(bf, size, "NONE");
940#define P_FLAG(n) \
941 if (flags & EFD_##n) { \
942 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
943 flags &= ~EFD_##n; \
944 }
945
946 P_FLAG(SEMAPHORE);
947 P_FLAG(CLOEXEC);
948 P_FLAG(NONBLOCK);
949#undef P_FLAG
950
951 if (flags)
952 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
953
954 return printed;
955}
956
957#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
958
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300959static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
960 struct syscall_arg *arg)
961{
962 int printed = 0, flags = arg->val;
963
964#define P_FLAG(n) \
965 if (flags & O_##n) { \
966 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
967 flags &= ~O_##n; \
968 }
969
970 P_FLAG(CLOEXEC);
971 P_FLAG(NONBLOCK);
972#undef P_FLAG
973
974 if (flags)
975 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
976
977 return printed;
978}
979
980#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
981
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300982static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
983{
984 int sig = arg->val;
985
986 switch (sig) {
987#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
988 P_SIGNUM(HUP);
989 P_SIGNUM(INT);
990 P_SIGNUM(QUIT);
991 P_SIGNUM(ILL);
992 P_SIGNUM(TRAP);
993 P_SIGNUM(ABRT);
994 P_SIGNUM(BUS);
995 P_SIGNUM(FPE);
996 P_SIGNUM(KILL);
997 P_SIGNUM(USR1);
998 P_SIGNUM(SEGV);
999 P_SIGNUM(USR2);
1000 P_SIGNUM(PIPE);
1001 P_SIGNUM(ALRM);
1002 P_SIGNUM(TERM);
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001003 P_SIGNUM(CHLD);
1004 P_SIGNUM(CONT);
1005 P_SIGNUM(STOP);
1006 P_SIGNUM(TSTP);
1007 P_SIGNUM(TTIN);
1008 P_SIGNUM(TTOU);
1009 P_SIGNUM(URG);
1010 P_SIGNUM(XCPU);
1011 P_SIGNUM(XFSZ);
1012 P_SIGNUM(VTALRM);
1013 P_SIGNUM(PROF);
1014 P_SIGNUM(WINCH);
1015 P_SIGNUM(IO);
1016 P_SIGNUM(PWR);
1017 P_SIGNUM(SYS);
Ben Hutchings02c5bb42014-02-06 01:00:41 +00001018#ifdef SIGEMT
1019 P_SIGNUM(EMT);
1020#endif
1021#ifdef SIGSTKFLT
1022 P_SIGNUM(STKFLT);
1023#endif
1024#ifdef SIGSWI
1025 P_SIGNUM(SWI);
1026#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001027 default: break;
1028 }
1029
1030 return scnprintf(bf, size, "%#x", sig);
1031}
1032
1033#define SCA_SIGNUM syscall_arg__scnprintf_signum
1034
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001035#if defined(__i386__) || defined(__x86_64__)
1036/*
1037 * FIXME: Make this available to all arches.
1038 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001039#define TCGETS 0x5401
1040
1041static const char *tioctls[] = {
1042 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
1043 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
1044 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
1045 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
1046 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
1047 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
1048 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
1049 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
1050 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
1051 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
1052 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
1053 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
1054 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
1055 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
1056 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
1057};
1058
1059static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001060#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001061
Arnaldo Carvalho de Melo6fb35b92016-04-13 11:50:23 -03001062#ifndef SECCOMP_SET_MODE_STRICT
1063#define SECCOMP_SET_MODE_STRICT 0
1064#endif
1065#ifndef SECCOMP_SET_MODE_FILTER
1066#define SECCOMP_SET_MODE_FILTER 1
1067#endif
1068
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001069static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg)
1070{
1071 int op = arg->val;
1072 size_t printed = 0;
1073
1074 switch (op) {
1075#define P_SECCOMP_SET_MODE_OP(n) case SECCOMP_SET_MODE_##n: printed = scnprintf(bf, size, #n); break
1076 P_SECCOMP_SET_MODE_OP(STRICT);
1077 P_SECCOMP_SET_MODE_OP(FILTER);
1078#undef P_SECCOMP_SET_MODE_OP
1079 default: printed = scnprintf(bf, size, "%#x", op); break;
1080 }
1081
1082 return printed;
1083}
1084
1085#define SCA_SECCOMP_OP syscall_arg__scnprintf_seccomp_op
1086
Arnaldo Carvalho de Melo6fb35b92016-04-13 11:50:23 -03001087#ifndef SECCOMP_FILTER_FLAG_TSYNC
1088#define SECCOMP_FILTER_FLAG_TSYNC 1
1089#endif
1090
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001091static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size,
1092 struct syscall_arg *arg)
1093{
1094 int printed = 0, flags = arg->val;
1095
1096#define P_FLAG(n) \
1097 if (flags & SECCOMP_FILTER_FLAG_##n) { \
1098 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
1099 flags &= ~SECCOMP_FILTER_FLAG_##n; \
1100 }
1101
1102 P_FLAG(TSYNC);
1103#undef P_FLAG
1104
1105 if (flags)
1106 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
1107
1108 return printed;
1109}
1110
1111#define SCA_SECCOMP_FLAGS syscall_arg__scnprintf_seccomp_flags
1112
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -03001113static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
1114 struct syscall_arg *arg)
1115{
1116 int printed = 0, flags = arg->val;
1117
1118#define P_FLAG(n) \
1119 if (flags & GRND_##n) { \
1120 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
1121 flags &= ~GRND_##n; \
1122 }
1123
1124 P_FLAG(RANDOM);
1125 P_FLAG(NONBLOCK);
1126#undef P_FLAG
1127
1128 if (flags)
1129 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
1130
1131 return printed;
1132}
1133
1134#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
1135
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001136#define STRARRAY(arg, name, array) \
1137 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
1138 .arg_parm = { [arg] = &strarray__##array, }
1139
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001140#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001141#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001142#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001143#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001144
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001145static struct syscall_fmt {
1146 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001147 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001148 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001149 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001150 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001151 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001152 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001153 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001154} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -03001155 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001156 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1157 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001158 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -03001159 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001160 { .name = "brk", .hexret = true,
1161 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001162 { .name = "chdir", .errmsg = true,
1163 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1164 { .name = "chmod", .errmsg = true,
1165 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1166 { .name = "chroot", .errmsg = true,
1167 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -06001168 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001169 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001170 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001171 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -03001172 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001173 { .name = "creat", .errmsg = true,
1174 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001175 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001176 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001177 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001178 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001179 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001180 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001181 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -03001182 { .name = "eventfd2", .errmsg = true,
1183 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001184 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001185 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1186 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001187 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001188 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001189 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001190 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001191 { .name = "fchdir", .errmsg = true,
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 = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001194 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001195 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001196 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1197 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001198 { .name = "fchown", .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 = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001201 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1202 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001203 { .name = "fcntl", .errmsg = true,
1204 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1205 [1] = SCA_STRARRAY, /* cmd */ },
1206 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1207 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001208 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -03001209 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001210 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1211 [1] = SCA_FLOCK, /* cmd */ }, },
1212 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001213 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001214 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001215 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001216 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001217 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1218 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001219 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001220 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001221 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001222 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001223 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001224 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -03001225 { .name = "futex", .errmsg = true,
1226 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001227 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001228 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1229 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001230 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001231 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001232 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001233 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001234 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001235 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001236 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001237 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -03001238 { .name = "getrandom", .errmsg = true,
1239 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001240 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001241 { .name = "getxattr", .errmsg = true,
1242 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1243 { .name = "inotify_add_watch", .errmsg = true,
1244 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001245 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001246 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001247#if defined(__i386__) || defined(__x86_64__)
1248/*
1249 * FIXME: Make this available to all arches.
1250 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001251 [1] = SCA_STRHEXARRAY, /* cmd */
1252 [2] = SCA_HEX, /* arg */ },
1253 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001254#else
1255 [2] = SCA_HEX, /* arg */ }, },
1256#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -03001257 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001258 { .name = "kill", .errmsg = true,
1259 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001260 { .name = "lchown", .errmsg = true,
1261 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1262 { .name = "lgetxattr", .errmsg = true,
1263 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001264 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001265 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001266 { .name = "listxattr", .errmsg = true,
1267 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001268 { .name = "llistxattr", .errmsg = true,
1269 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1270 { .name = "lremovexattr", .errmsg = true,
1271 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001272 { .name = "lseek", .errmsg = true,
1273 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1274 [2] = SCA_STRARRAY, /* whence */ },
1275 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001276 { .name = "lsetxattr", .errmsg = true,
1277 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001278 { .name = "lstat", .errmsg = true, .alias = "newlstat",
1279 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001280 { .name = "lsxattr", .errmsg = true,
1281 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001282 { .name = "madvise", .errmsg = true,
1283 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1284 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001285 { .name = "mkdir", .errmsg = true,
1286 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001287 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001288 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1289 [1] = SCA_FILENAME, /* pathname */ }, },
1290 { .name = "mknod", .errmsg = true,
1291 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001292 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001293 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1294 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001295 { .name = "mlock", .errmsg = true,
1296 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1297 { .name = "mlockall", .errmsg = true,
1298 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001299 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001300 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001301 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001302 [3] = SCA_MMAP_FLAGS, /* flags */
1303 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001304 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001305 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1306 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001307 { .name = "mq_unlink", .errmsg = true,
1308 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001309 { .name = "mremap", .hexret = true,
1310 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001311 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001312 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001313 { .name = "munlock", .errmsg = true,
1314 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001315 { .name = "munmap", .errmsg = true,
1316 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001317 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001318 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001319 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001320 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1321 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001322 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001323 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1324 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001325 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001326 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1327 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001328 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001329 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001330 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001331 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001332 { .name = "perf_event_open", .errmsg = true,
1333 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1334 [2] = SCA_INT, /* cpu */
1335 [3] = SCA_FD, /* group_fd */
1336 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001337 { .name = "pipe2", .errmsg = true,
1338 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001339 { .name = "poll", .errmsg = true, .timeout = true, },
1340 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001341 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001342 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001343 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001344 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001345 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001346 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001347 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001348 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001349 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001350 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001351 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001352 { .name = "readlink", .errmsg = true,
1353 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001354 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001355 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1356 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001357 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001358 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001359 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001360 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1361 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001362 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001363 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1364 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001365 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001366 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1367 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001368 { .name = "removexattr", .errmsg = true,
1369 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001370 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001371 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001372 { .name = "rmdir", .errmsg = true,
1373 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001374 { .name = "rt_sigaction", .errmsg = true,
1375 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001376 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001377 { .name = "rt_sigqueueinfo", .errmsg = true,
1378 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1379 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1380 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001381 { .name = "sched_setscheduler", .errmsg = true,
1382 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001383 { .name = "seccomp", .errmsg = true,
1384 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
1385 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001386 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001387 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001388 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1389 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001390 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001391 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1392 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001393 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001394 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1395 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001396 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001397 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001398 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001399 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001400 { .name = "setxattr", .errmsg = true,
1401 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001402 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001403 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001404 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001405 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1406 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001407 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001408 { .name = "socketpair", .errmsg = true,
1409 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1410 [1] = SCA_SK_TYPE, /* type */ },
1411 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001412 { .name = "stat", .errmsg = true, .alias = "newstat",
1413 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001414 { .name = "statfs", .errmsg = true,
1415 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1416 { .name = "swapoff", .errmsg = true,
1417 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1418 { .name = "swapon", .errmsg = true,
1419 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001420 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001421 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001422 { .name = "tgkill", .errmsg = true,
1423 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1424 { .name = "tkill", .errmsg = true,
1425 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001426 { .name = "truncate", .errmsg = true,
1427 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001428 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001429 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001430 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1431 [1] = SCA_FILENAME, /* pathname */ }, },
1432 { .name = "utime", .errmsg = true,
1433 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001434 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001435 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1436 [1] = SCA_FILENAME, /* filename */ }, },
1437 { .name = "utimes", .errmsg = true,
1438 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001439 { .name = "vmsplice", .errmsg = true,
1440 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001441 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001442 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001443 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001444 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001445 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001446 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001447 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001448 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001449};
1450
1451static int syscall_fmt__cmp(const void *name, const void *fmtp)
1452{
1453 const struct syscall_fmt *fmt = fmtp;
1454 return strcmp(name, fmt->name);
1455}
1456
1457static struct syscall_fmt *syscall_fmt__find(const char *name)
1458{
1459 const int nmemb = ARRAY_SIZE(syscall_fmts);
1460 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1461}
1462
1463struct syscall {
1464 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001465 int nr_args;
1466 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001467 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001468 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001469 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001470 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001471 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001472};
1473
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001474static size_t fprintf_duration(unsigned long t, FILE *fp)
1475{
1476 double duration = (double)t / NSEC_PER_MSEC;
1477 size_t printed = fprintf(fp, "(");
1478
1479 if (duration >= 1.0)
1480 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1481 else if (duration >= 0.01)
1482 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1483 else
1484 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001485 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001486}
1487
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001488/**
1489 * filename.ptr: The filename char pointer that will be vfs_getname'd
1490 * filename.entry_str_pos: Where to insert the string translated from
1491 * filename.ptr by the vfs_getname tracepoint/kprobe.
1492 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001493struct thread_trace {
1494 u64 entry_time;
1495 u64 exit_time;
1496 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001497 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001498 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001499 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001500 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001501 struct {
1502 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001503 short int entry_str_pos;
1504 bool pending_open;
1505 unsigned int namelen;
1506 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001507 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001508 struct {
1509 int max;
1510 char **table;
1511 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001512
1513 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001514};
1515
1516static struct thread_trace *thread_trace__new(void)
1517{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001518 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1519
1520 if (ttrace)
1521 ttrace->paths.max = -1;
1522
David Ahernbf2575c2013-10-08 21:26:53 -06001523 ttrace->syscall_stats = intlist__new(NULL);
1524
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001525 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001526}
1527
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001528static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001529{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001530 struct thread_trace *ttrace;
1531
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001532 if (thread == NULL)
1533 goto fail;
1534
Namhyung Kim89dceb22014-10-06 09:46:03 +09001535 if (thread__priv(thread) == NULL)
1536 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001537
Namhyung Kim89dceb22014-10-06 09:46:03 +09001538 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001539 goto fail;
1540
Namhyung Kim89dceb22014-10-06 09:46:03 +09001541 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001542 ++ttrace->nr_events;
1543
1544 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001545fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001546 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001547 "WARNING: not enough memory, dropping samples!\n");
1548 return NULL;
1549}
1550
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001551#define TRACE_PFMAJ (1 << 0)
1552#define TRACE_PFMIN (1 << 1)
1553
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001554static const size_t trace__entry_str_size = 2048;
1555
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001556static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001557{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001558 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001559
1560 if (fd > ttrace->paths.max) {
1561 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1562
1563 if (npath == NULL)
1564 return -1;
1565
1566 if (ttrace->paths.max != -1) {
1567 memset(npath + ttrace->paths.max + 1, 0,
1568 (fd - ttrace->paths.max) * sizeof(char *));
1569 } else {
1570 memset(npath, 0, (fd + 1) * sizeof(char *));
1571 }
1572
1573 ttrace->paths.table = npath;
1574 ttrace->paths.max = fd;
1575 }
1576
1577 ttrace->paths.table[fd] = strdup(pathname);
1578
1579 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1580}
1581
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001582static int thread__read_fd_path(struct thread *thread, int fd)
1583{
1584 char linkname[PATH_MAX], pathname[PATH_MAX];
1585 struct stat st;
1586 int ret;
1587
1588 if (thread->pid_ == thread->tid) {
1589 scnprintf(linkname, sizeof(linkname),
1590 "/proc/%d/fd/%d", thread->pid_, fd);
1591 } else {
1592 scnprintf(linkname, sizeof(linkname),
1593 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1594 }
1595
1596 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1597 return -1;
1598
1599 ret = readlink(linkname, pathname, sizeof(pathname));
1600
1601 if (ret < 0 || ret > st.st_size)
1602 return -1;
1603
1604 pathname[ret] = '\0';
1605 return trace__set_fd_pathname(thread, fd, pathname);
1606}
1607
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001608static const char *thread__fd_path(struct thread *thread, int fd,
1609 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001610{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001611 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001612
1613 if (ttrace == NULL)
1614 return NULL;
1615
1616 if (fd < 0)
1617 return NULL;
1618
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001619 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001620 if (!trace->live)
1621 return NULL;
1622 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001623 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001624 return NULL;
1625 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001626
1627 return ttrace->paths.table[fd];
1628}
1629
1630static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1631 struct syscall_arg *arg)
1632{
1633 int fd = arg->val;
1634 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001635 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001636
1637 if (path)
1638 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1639
1640 return printed;
1641}
1642
1643static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1644 struct syscall_arg *arg)
1645{
1646 int fd = arg->val;
1647 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001648 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001649
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001650 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1651 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001652
1653 return printed;
1654}
1655
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001656static void thread__set_filename_pos(struct thread *thread, const char *bf,
1657 unsigned long ptr)
1658{
1659 struct thread_trace *ttrace = thread__priv(thread);
1660
1661 ttrace->filename.ptr = ptr;
1662 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1663}
1664
1665static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1666 struct syscall_arg *arg)
1667{
1668 unsigned long ptr = arg->val;
1669
1670 if (!arg->trace->vfs_getname)
1671 return scnprintf(bf, size, "%#x", ptr);
1672
1673 thread__set_filename_pos(arg->thread, bf, ptr);
1674 return 0;
1675}
1676
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001677static bool trace__filter_duration(struct trace *trace, double t)
1678{
1679 return t < (trace->duration_filter * NSEC_PER_MSEC);
1680}
1681
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001682static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1683{
1684 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1685
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001686 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001687}
1688
Namhyung Kimf15eb532012-10-05 14:02:16 +09001689static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001690static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001691
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001692static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001693{
1694 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001695 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001696}
1697
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001698static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001699 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001700{
1701 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001702 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001703
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001704 if (trace->multiple_threads) {
1705 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001706 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001707 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001708 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001709
1710 return printed;
1711}
1712
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001713static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001714 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001715{
1716 int ret = 0;
1717
1718 switch (event->header.type) {
1719 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001720 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001721 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001722 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001723 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001724 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001725 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001726 break;
1727 }
1728
1729 return ret;
1730}
1731
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001732static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001733 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001734 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001735 struct machine *machine)
1736{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001737 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001738 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001739}
1740
1741static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1742{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001743 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001744
1745 if (err)
1746 return err;
1747
David Ahern8fb598e2013-09-28 13:13:00 -06001748 trace->host = machine__new_host();
1749 if (trace->host == NULL)
1750 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001751
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001752 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001753 return -errno;
1754
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001755 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001756 evlist->threads, trace__tool_process, false,
1757 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001758 if (err)
1759 symbol__exit();
1760
1761 return err;
1762}
1763
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001764static int syscall__set_arg_fmts(struct syscall *sc)
1765{
1766 struct format_field *field;
1767 int idx = 0;
1768
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001769 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001770 if (sc->arg_scnprintf == NULL)
1771 return -1;
1772
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001773 if (sc->fmt)
1774 sc->arg_parm = sc->fmt->arg_parm;
1775
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001776 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001777 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1778 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1779 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001780 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001781 else if (strcmp(field->type, "pid_t") == 0)
1782 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001783 else if (strcmp(field->type, "umode_t") == 0)
1784 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001785 ++idx;
1786 }
1787
1788 return 0;
1789}
1790
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001791static int trace__read_syscall_info(struct trace *trace, int id)
1792{
1793 char tp_name[128];
1794 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001795 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001796
1797 if (name == NULL)
1798 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001799
1800 if (id > trace->syscalls.max) {
1801 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1802
1803 if (nsyscalls == NULL)
1804 return -1;
1805
1806 if (trace->syscalls.max != -1) {
1807 memset(nsyscalls + trace->syscalls.max + 1, 0,
1808 (id - trace->syscalls.max) * sizeof(*sc));
1809 } else {
1810 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1811 }
1812
1813 trace->syscalls.table = nsyscalls;
1814 trace->syscalls.max = id;
1815 }
1816
1817 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001818 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001819
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001820 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001821
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001822 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001823 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001824
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001825 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001826 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001827 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001828 }
1829
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001830 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001831 return -1;
1832
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001833 sc->args = sc->tp_format->format.fields;
1834 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001835 /*
1836 * We need to check and discard the first variable '__syscall_nr'
1837 * or 'nr' that mean the syscall number. It is needless here.
1838 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1839 */
1840 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001841 sc->args = sc->args->next;
1842 --sc->nr_args;
1843 }
1844
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001845 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1846
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001847 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001848}
1849
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001850static int trace__validate_ev_qualifier(struct trace *trace)
1851{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001852 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001853 struct str_node *pos;
1854
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001855 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1856 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1857 sizeof(trace->ev_qualifier_ids.entries[0]));
1858
1859 if (trace->ev_qualifier_ids.entries == NULL) {
1860 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1861 trace->output);
1862 err = -EINVAL;
1863 goto out;
1864 }
1865
1866 i = 0;
1867
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001868 strlist__for_each(pos, trace->ev_qualifier) {
1869 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001870 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001871
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001872 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001873 if (err == 0) {
1874 fputs("Error:\tInvalid syscall ", trace->output);
1875 err = -EINVAL;
1876 } else {
1877 fputs(", ", trace->output);
1878 }
1879
1880 fputs(sc, trace->output);
1881 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001882
1883 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001884 }
1885
1886 if (err < 0) {
1887 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1888 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001889 zfree(&trace->ev_qualifier_ids.entries);
1890 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001891 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001892out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001893 return err;
1894}
1895
David Ahern55d43bc2015-02-19 15:00:22 -05001896/*
1897 * args is to be interpreted as a series of longs but we need to handle
1898 * 8-byte unaligned accesses. args points to raw_data within the event
1899 * and raw_data is guaranteed to be 8-byte unaligned because it is
1900 * preceded by raw_size which is a u32. So we need to copy args to a temp
1901 * variable to read it. Most notably this avoids extended load instructions
1902 * on unaligned addresses
1903 */
1904
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001905static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001906 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001907 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001908{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001909 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001910 unsigned char *p;
1911 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001912
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001913 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001914 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001915 u8 bit = 1;
1916 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001917 .idx = 0,
1918 .mask = 0,
1919 .trace = trace,
1920 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001921 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001922
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001923 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001924 field = field->next, ++arg.idx, bit <<= 1) {
1925 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001926 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001927
1928 /* special care for unaligned accesses */
1929 p = args + sizeof(unsigned long) * arg.idx;
1930 memcpy(&val, p, sizeof(val));
1931
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001932 /*
1933 * Suppress this argument if its value is zero and
1934 * and we don't have a string associated in an
1935 * strarray for it.
1936 */
David Ahern55d43bc2015-02-19 15:00:22 -05001937 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001938 !(sc->arg_scnprintf &&
1939 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1940 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001941 continue;
1942
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001943 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001944 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001945 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001946 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001947 if (sc->arg_parm)
1948 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001949 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1950 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001951 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001952 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001953 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001954 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001955 }
1956 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001957 int i = 0;
1958
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001959 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001960 /* special care for unaligned accesses */
1961 p = args + sizeof(unsigned long) * i;
1962 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001963 printed += scnprintf(bf + printed, size - printed,
1964 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001965 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001966 ++i;
1967 }
1968 }
1969
1970 return printed;
1971}
1972
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001973typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001974 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001975 struct perf_sample *sample);
1976
1977static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001978 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001979{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001980
1981 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001982
1983 /*
1984 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1985 * before that, leaving at a higher verbosity level till that is
1986 * explained. Reproduced with plain ftrace with:
1987 *
1988 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1989 * grep "NR -1 " /t/trace_pipe
1990 *
1991 * After generating some load on the machine.
1992 */
1993 if (verbose > 1) {
1994 static u64 n;
1995 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1996 id, perf_evsel__name(evsel), ++n);
1997 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001998 return NULL;
1999 }
2000
2001 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
2002 trace__read_syscall_info(trace, id))
2003 goto out_cant_read;
2004
2005 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
2006 goto out_cant_read;
2007
2008 return &trace->syscalls.table[id];
2009
2010out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002011 if (verbose) {
2012 fprintf(trace->output, "Problems reading syscall %d", id);
2013 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
2014 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
2015 fputs(" information\n", trace->output);
2016 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002017 return NULL;
2018}
2019
David Ahernbf2575c2013-10-08 21:26:53 -06002020static void thread__update_stats(struct thread_trace *ttrace,
2021 int id, struct perf_sample *sample)
2022{
2023 struct int_node *inode;
2024 struct stats *stats;
2025 u64 duration = 0;
2026
2027 inode = intlist__findnew(ttrace->syscall_stats, id);
2028 if (inode == NULL)
2029 return;
2030
2031 stats = inode->priv;
2032 if (stats == NULL) {
2033 stats = malloc(sizeof(struct stats));
2034 if (stats == NULL)
2035 return;
2036 init_stats(stats);
2037 inode->priv = stats;
2038 }
2039
2040 if (ttrace->entry_time && sample->time > ttrace->entry_time)
2041 duration = sample->time - ttrace->entry_time;
2042
2043 update_stats(stats, duration);
2044}
2045
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03002046static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
2047{
2048 struct thread_trace *ttrace;
2049 u64 duration;
2050 size_t printed;
2051
2052 if (trace->current == NULL)
2053 return 0;
2054
2055 ttrace = thread__priv(trace->current);
2056
2057 if (!ttrace->entry_pending)
2058 return 0;
2059
2060 duration = sample->time - ttrace->entry_time;
2061
2062 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
2063 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
2064 ttrace->entry_pending = false;
2065
2066 return printed;
2067}
2068
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002069static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002070 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002071 struct perf_sample *sample)
2072{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002073 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002074 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002075 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002076 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002077 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002078 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002079 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002080
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002081 if (sc == NULL)
2082 return -1;
2083
David Ahern8fb598e2013-09-28 13:13:00 -06002084 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002085 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002086 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002087 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002088
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002089 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002090
2091 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002092 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002093 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002094 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002095 }
2096
David Ahern13f22a22015-03-19 12:23:03 -06002097 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03002098 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03002099
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002100 ttrace->entry_time = sample->time;
2101 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002102 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002103
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002104 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002105 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002106
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03002107 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07002108 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002109 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
2110 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002111 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002112 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002113 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002114 /* See trace__vfs_getname & trace__sys_exit */
2115 ttrace->filename.pending_open = false;
2116 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002117
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002118 if (trace->current != thread) {
2119 thread__put(trace->current);
2120 trace->current = thread__get(thread);
2121 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002122 err = 0;
2123out_put:
2124 thread__put(thread);
2125 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002126}
2127
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03002128static int trace__fprintf_callchain(struct trace *trace, struct perf_evsel *evsel,
2129 struct perf_sample *sample)
2130{
2131 struct addr_location al;
2132 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03002133 const unsigned int print_opts = EVSEL__PRINT_SYM |
2134 EVSEL__PRINT_DSO |
2135 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03002136
2137 if (sample->callchain == NULL)
2138 return 0;
2139
2140 if (machine__resolve(trace->host, &al, sample) < 0) {
2141 pr_err("Problem processing %s callchain, skipping...\n",
2142 perf_evsel__name(evsel));
2143 return 0;
2144 }
2145
2146 return perf_evsel__fprintf_callchain(evsel, sample, &al, 38, print_opts,
2147 scripting_max_stack, trace->output);
2148}
2149
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002150static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002151 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002152 struct perf_sample *sample)
2153{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002154 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002155 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002156 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002157 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002158 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002159 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002160
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002161 if (sc == NULL)
2162 return -1;
2163
David Ahern8fb598e2013-09-28 13:13:00 -06002164 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002165 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002166 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002167 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002168
David Ahernbf2575c2013-10-08 21:26:53 -06002169 if (trace->summary)
2170 thread__update_stats(ttrace, id, sample);
2171
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002172 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002173
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002174 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002175 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
2176 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002177 ++trace->stats.vfs_getname;
2178 }
2179
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002180 ttrace->exit_time = sample->time;
2181
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002182 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002183 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002184 if (trace__filter_duration(trace, duration))
2185 goto out;
2186 } else if (trace->duration_filter)
2187 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002188
David Ahernfd2eaba2013-11-12 09:31:15 -07002189 if (trace->summary_only)
2190 goto out;
2191
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002192 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002193
2194 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002195 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002196 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002197 fprintf(trace->output, " ... [");
2198 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
2199 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002200 }
2201
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002202 if (sc->fmt == NULL) {
2203signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002204 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03002205 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00002206 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002207 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
2208 *e = audit_errno_to_name(-ret);
2209
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002210 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002211 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002212 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03002213 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002214 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03002215 else if (sc->fmt->errpid) {
2216 struct thread *child = machine__find_thread(trace->host, ret, ret);
2217
2218 if (child != NULL) {
2219 fprintf(trace->output, ") = %ld", ret);
2220 if (child->comm_set)
2221 fprintf(trace->output, " (%s)", thread__comm_str(child));
2222 thread__put(child);
2223 }
2224 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002225 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002226
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002227 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02002228
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03002229 trace__fprintf_callchain(trace, evsel, sample);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002230out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002231 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002232 err = 0;
2233out_put:
2234 thread__put(thread);
2235 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002236}
2237
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002238static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002239 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002240 struct perf_sample *sample)
2241{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002242 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2243 struct thread_trace *ttrace;
2244 size_t filename_len, entry_str_len, to_move;
2245 ssize_t remaining_space;
2246 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002247 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002248
2249 if (!thread)
2250 goto out;
2251
2252 ttrace = thread__priv(thread);
2253 if (!ttrace)
2254 goto out;
2255
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002256 filename_len = strlen(filename);
2257
2258 if (ttrace->filename.namelen < filename_len) {
2259 char *f = realloc(ttrace->filename.name, filename_len + 1);
2260
2261 if (f == NULL)
2262 goto out;
2263
2264 ttrace->filename.namelen = filename_len;
2265 ttrace->filename.name = f;
2266 }
2267
2268 strcpy(ttrace->filename.name, filename);
2269 ttrace->filename.pending_open = true;
2270
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002271 if (!ttrace->filename.ptr)
2272 goto out;
2273
2274 entry_str_len = strlen(ttrace->entry_str);
2275 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2276 if (remaining_space <= 0)
2277 goto out;
2278
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002279 if (filename_len > (size_t)remaining_space) {
2280 filename += filename_len - remaining_space;
2281 filename_len = remaining_space;
2282 }
2283
2284 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2285 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2286 memmove(pos + filename_len, pos, to_move);
2287 memcpy(pos, filename, filename_len);
2288
2289 ttrace->filename.ptr = 0;
2290 ttrace->filename.entry_str_pos = 0;
2291out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002292 return 0;
2293}
2294
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002295static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002296 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002297 struct perf_sample *sample)
2298{
2299 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2300 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06002301 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03002302 sample->pid,
2303 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002304 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002305
2306 if (ttrace == NULL)
2307 goto out_dump;
2308
2309 ttrace->runtime_ms += runtime_ms;
2310 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002311 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002312 return 0;
2313
2314out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002315 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002316 evsel->name,
2317 perf_evsel__strval(evsel, sample, "comm"),
2318 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2319 runtime,
2320 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002321 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002322 return 0;
2323}
2324
Wang Nan1d6c9402016-02-26 09:31:55 +00002325static void bpf_output__printer(enum binary_printer_ops op,
2326 unsigned int val, void *extra)
2327{
2328 FILE *output = extra;
2329 unsigned char ch = (unsigned char)val;
2330
2331 switch (op) {
2332 case BINARY_PRINT_CHAR_DATA:
2333 fprintf(output, "%c", isprint(ch) ? ch : '.');
2334 break;
2335 case BINARY_PRINT_DATA_BEGIN:
2336 case BINARY_PRINT_LINE_BEGIN:
2337 case BINARY_PRINT_ADDR:
2338 case BINARY_PRINT_NUM_DATA:
2339 case BINARY_PRINT_NUM_PAD:
2340 case BINARY_PRINT_SEP:
2341 case BINARY_PRINT_CHAR_PAD:
2342 case BINARY_PRINT_LINE_END:
2343 case BINARY_PRINT_DATA_END:
2344 default:
2345 break;
2346 }
2347}
2348
2349static void bpf_output__fprintf(struct trace *trace,
2350 struct perf_sample *sample)
2351{
2352 print_binary(sample->raw_data, sample->raw_size, 8,
2353 bpf_output__printer, trace->output);
2354}
2355
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002356static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2357 union perf_event *event __maybe_unused,
2358 struct perf_sample *sample)
2359{
2360 trace__printf_interrupted_entry(trace, sample);
2361 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002362
2363 if (trace->trace_syscalls)
2364 fprintf(trace->output, "( ): ");
2365
2366 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002367
Wang Nan1d6c9402016-02-26 09:31:55 +00002368 if (perf_evsel__is_bpf_output(evsel)) {
2369 bpf_output__fprintf(trace, sample);
2370 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002371 event_format__fprintf(evsel->tp_format, sample->cpu,
2372 sample->raw_data, sample->raw_size,
2373 trace->output);
2374 }
2375
2376 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03002377
2378 trace__fprintf_callchain(trace, evsel, sample);
2379
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002380 return 0;
2381}
2382
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002383static void print_location(FILE *f, struct perf_sample *sample,
2384 struct addr_location *al,
2385 bool print_dso, bool print_sym)
2386{
2387
2388 if ((verbose || print_dso) && al->map)
2389 fprintf(f, "%s@", al->map->dso->long_name);
2390
2391 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002392 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002393 al->addr - al->sym->start);
2394 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002395 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002396 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002397 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002398}
2399
2400static int trace__pgfault(struct trace *trace,
2401 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002402 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002403 struct perf_sample *sample)
2404{
2405 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002406 struct addr_location al;
2407 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002408 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002409 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002410
2411 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002412 ttrace = thread__trace(thread, trace->output);
2413 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002414 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002415
2416 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2417 ttrace->pfmaj++;
2418 else
2419 ttrace->pfmin++;
2420
2421 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002422 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002423
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002424 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002425 sample->ip, &al);
2426
2427 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2428
2429 fprintf(trace->output, "%sfault [",
2430 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2431 "maj" : "min");
2432
2433 print_location(trace->output, sample, &al, false, true);
2434
2435 fprintf(trace->output, "] => ");
2436
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002437 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002438 sample->addr, &al);
2439
2440 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002441 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002442 MAP__FUNCTION, sample->addr, &al);
2443
2444 if (al.map)
2445 map_type = 'x';
2446 else
2447 map_type = '?';
2448 }
2449
2450 print_location(trace->output, sample, &al, true, false);
2451
2452 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002453out:
2454 err = 0;
2455out_put:
2456 thread__put(thread);
2457 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002458}
2459
David Ahernbdc89662013-08-28 22:29:53 -06002460static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2461{
2462 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2463 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2464 return false;
2465
2466 if (trace->pid_list || trace->tid_list)
2467 return true;
2468
2469 return false;
2470}
2471
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002472static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002473 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002474 struct perf_sample *sample)
2475{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002476 /*
2477 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2478 * and don't use sample->time unconditionally, we may end up having
2479 * some other event in the future without PERF_SAMPLE_TIME for good
2480 * reason, i.e. we may not be interested in its timestamps, just in
2481 * it taking place, picking some piece of information when it
2482 * appears in our event stream (vfs_getname comes to mind).
2483 */
2484 if (trace->base_time == 0 && !trace->full_time &&
2485 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002486 trace->base_time = sample->time;
2487}
2488
David Ahern6810fc92013-08-28 22:29:52 -06002489static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002490 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002491 struct perf_sample *sample,
2492 struct perf_evsel *evsel,
2493 struct machine *machine __maybe_unused)
2494{
2495 struct trace *trace = container_of(tool, struct trace, tool);
2496 int err = 0;
2497
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002498 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002499
David Ahernbdc89662013-08-28 22:29:53 -06002500 if (skip_sample(trace, sample))
2501 return 0;
2502
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002503 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002504
David Ahern31605652013-12-04 19:41:41 -07002505 if (handler) {
2506 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002507 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002508 }
David Ahern6810fc92013-08-28 22:29:52 -06002509
2510 return err;
2511}
2512
David Ahernbdc89662013-08-28 22:29:53 -06002513static int parse_target_str(struct trace *trace)
2514{
2515 if (trace->opts.target.pid) {
2516 trace->pid_list = intlist__new(trace->opts.target.pid);
2517 if (trace->pid_list == NULL) {
2518 pr_err("Error parsing process id string\n");
2519 return -EINVAL;
2520 }
2521 }
2522
2523 if (trace->opts.target.tid) {
2524 trace->tid_list = intlist__new(trace->opts.target.tid);
2525 if (trace->tid_list == NULL) {
2526 pr_err("Error parsing thread id string\n");
2527 return -EINVAL;
2528 }
2529 }
2530
2531 return 0;
2532}
2533
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002534static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002535{
2536 unsigned int rec_argc, i, j;
2537 const char **rec_argv;
2538 const char * const record_args[] = {
2539 "record",
2540 "-R",
2541 "-m", "1024",
2542 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002543 };
2544
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002545 const char * const sc_args[] = { "-e", };
2546 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2547 const char * const majpf_args[] = { "-e", "major-faults" };
2548 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2549 const char * const minpf_args[] = { "-e", "minor-faults" };
2550 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2551
David Ahern9aca7f12013-12-04 19:41:39 -07002552 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002553 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2554 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002555 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2556
2557 if (rec_argv == NULL)
2558 return -ENOMEM;
2559
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002560 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002561 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002562 rec_argv[j++] = record_args[i];
2563
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002564 if (trace->trace_syscalls) {
2565 for (i = 0; i < sc_args_nr; i++)
2566 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002567
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002568 /* event string may be different for older kernels - e.g., RHEL6 */
2569 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2570 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2571 else if (is_valid_tracepoint("syscalls:sys_enter"))
2572 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2573 else {
2574 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2575 return -1;
2576 }
David Ahern9aca7f12013-12-04 19:41:39 -07002577 }
David Ahern9aca7f12013-12-04 19:41:39 -07002578
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002579 if (trace->trace_pgfaults & TRACE_PFMAJ)
2580 for (i = 0; i < majpf_args_nr; i++)
2581 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002582
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002583 if (trace->trace_pgfaults & TRACE_PFMIN)
2584 for (i = 0; i < minpf_args_nr; i++)
2585 rec_argv[j++] = minpf_args[i];
2586
2587 for (i = 0; i < (unsigned int)argc; i++)
2588 rec_argv[j++] = argv[i];
2589
2590 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002591}
2592
David Ahernbf2575c2013-10-08 21:26:53 -06002593static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2594
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002595static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002596{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002597 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002598
2599 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002600 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002601
2602 if (perf_evsel__field(evsel, "pathname") == NULL) {
2603 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002604 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002605 }
2606
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002607 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002608 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002609 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002610}
2611
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002612static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2613 u64 config)
2614{
2615 struct perf_evsel *evsel;
2616 struct perf_event_attr attr = {
2617 .type = PERF_TYPE_SOFTWARE,
2618 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002619 };
2620
2621 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002622 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002623
2624 event_attr_init(&attr);
2625
2626 evsel = perf_evsel__new(&attr);
2627 if (!evsel)
2628 return -ENOMEM;
2629
2630 evsel->handler = trace__pgfault;
2631 perf_evlist__add(evlist, evsel);
2632
2633 return 0;
2634}
2635
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002636static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2637{
2638 const u32 type = event->header.type;
2639 struct perf_evsel *evsel;
2640
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002641 if (type != PERF_RECORD_SAMPLE) {
2642 trace__process_event(trace, trace->host, event, sample);
2643 return;
2644 }
2645
2646 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2647 if (evsel == NULL) {
2648 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2649 return;
2650 }
2651
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002652 trace__set_base_time(trace, evsel, sample);
2653
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002654 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2655 sample->raw_data == NULL) {
2656 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2657 perf_evsel__name(evsel), sample->tid,
2658 sample->cpu, sample->raw_size);
2659 } else {
2660 tracepoint_handler handler = evsel->handler;
2661 handler(trace, evsel, event, sample);
2662 }
2663}
2664
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002665static int trace__add_syscall_newtp(struct trace *trace)
2666{
2667 int ret = -1;
2668 struct perf_evlist *evlist = trace->evlist;
2669 struct perf_evsel *sys_enter, *sys_exit;
2670
2671 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2672 if (sys_enter == NULL)
2673 goto out;
2674
2675 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2676 goto out_delete_sys_enter;
2677
2678 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2679 if (sys_exit == NULL)
2680 goto out_delete_sys_enter;
2681
2682 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2683 goto out_delete_sys_exit;
2684
2685 perf_evlist__add(evlist, sys_enter);
2686 perf_evlist__add(evlist, sys_exit);
2687
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002688 if (trace->opts.callgraph_set && !trace->kernel_syscallchains) {
2689 /*
2690 * We're interested only in the user space callchain
2691 * leading to the syscall, allow overriding that for
2692 * debugging reasons using --kernel_syscall_callchains
2693 */
2694 sys_exit->attr.exclude_callchain_kernel = 1;
2695 }
2696
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002697 trace->syscalls.events.sys_enter = sys_enter;
2698 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002699
2700 ret = 0;
2701out:
2702 return ret;
2703
2704out_delete_sys_exit:
2705 perf_evsel__delete_priv(sys_exit);
2706out_delete_sys_enter:
2707 perf_evsel__delete_priv(sys_enter);
2708 goto out;
2709}
2710
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002711static int trace__set_ev_qualifier_filter(struct trace *trace)
2712{
2713 int err = -1;
2714 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2715 trace->ev_qualifier_ids.nr,
2716 trace->ev_qualifier_ids.entries);
2717
2718 if (filter == NULL)
2719 goto out_enomem;
2720
2721 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2722 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2723
2724 free(filter);
2725out:
2726 return err;
2727out_enomem:
2728 errno = ENOMEM;
2729 goto out;
2730}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002731
Namhyung Kimf15eb532012-10-05 14:02:16 +09002732static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002733{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002734 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002735 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002736 int err = -1, i;
2737 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002738 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002739 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002740
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002741 trace->live = true;
2742
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002743 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002744 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002745
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002746 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002747 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002748
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002749 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002750 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002751 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002752 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002753
2754 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2755 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002756 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002757
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002758 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002759 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2760 trace__sched_stat_runtime))
2761 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002762
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002763 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2764 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002765 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002766 goto out_delete_evlist;
2767 }
2768
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002769 err = trace__symbols_init(trace, evlist);
2770 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002771 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002772 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002773 }
2774
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002775 perf_evlist__config(evlist, &trace->opts, NULL);
2776
2777 if (trace->opts.callgraph_set && trace->syscalls.events.sys_exit) {
2778 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2779 &trace->opts, &callchain_param);
2780 /*
2781 * Now we have evsels with different sample_ids, use
2782 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2783 * from a fixed position in each ring buffer record.
2784 *
2785 * As of this the changeset introducing this comment, this
2786 * isn't strictly needed, as the fields that can come before
2787 * PERF_SAMPLE_ID are all used, but we'll probably disable
2788 * some of those for things like copying the payload of
2789 * pointer syscall arguments, and for vfs_getname we don't
2790 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2791 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2792 */
2793 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2794 perf_evlist__reset_sample_bit(evlist, ID);
2795 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002796
Namhyung Kimf15eb532012-10-05 14:02:16 +09002797 signal(SIGCHLD, sig_handler);
2798 signal(SIGINT, sig_handler);
2799
2800 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002801 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002802 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002803 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002804 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002805 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002806 }
2807 }
2808
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002809 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002810 if (err < 0)
2811 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002812
Wang Nanba504232016-02-26 09:31:54 +00002813 err = bpf__apply_obj_config();
2814 if (err) {
2815 char errbuf[BUFSIZ];
2816
2817 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2818 pr_err("ERROR: Apply config to BPF failed: %s\n",
2819 errbuf);
2820 goto out_error_open;
2821 }
2822
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002823 /*
2824 * Better not use !target__has_task() here because we need to cover the
2825 * case where no threads were specified in the command line, but a
2826 * workload was, and in that case we will fill in the thread_map when
2827 * we fork the workload in perf_evlist__prepare_workload.
2828 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002829 if (trace->filter_pids.nr > 0)
2830 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002831 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002832 err = perf_evlist__set_filter_pid(evlist, getpid());
2833
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002834 if (err < 0)
2835 goto out_error_mem;
2836
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002837 if (trace->ev_qualifier_ids.nr > 0) {
2838 err = trace__set_ev_qualifier_filter(trace);
2839 if (err < 0)
2840 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002841
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002842 pr_debug("event qualifier tracepoint filter: %s\n",
2843 trace->syscalls.events.sys_exit->filter);
2844 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002845
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002846 err = perf_evlist__apply_filters(evlist, &evsel);
2847 if (err < 0)
2848 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002849
Jiri Olsaf8850372013-11-28 17:57:22 +01002850 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002851 if (err < 0)
2852 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002853
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002854 if (!target__none(&trace->opts.target))
2855 perf_evlist__enable(evlist);
2856
Namhyung Kimf15eb532012-10-05 14:02:16 +09002857 if (forks)
2858 perf_evlist__start_workload(evlist);
2859
Jiri Olsae13798c2015-06-23 00:36:02 +02002860 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002861 evlist->threads->nr > 1 ||
2862 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002863again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002864 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002865
2866 for (i = 0; i < evlist->nr_mmaps; i++) {
2867 union perf_event *event;
2868
2869 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002870 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002871
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002872 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002873
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002874 err = perf_evlist__parse_sample(evlist, event, &sample);
2875 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002876 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002877 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002878 }
2879
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002880 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002881next_event:
2882 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002883
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002884 if (interrupted)
2885 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002886
2887 if (done && !draining) {
2888 perf_evlist__disable(evlist);
2889 draining = true;
2890 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002891 }
2892 }
2893
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002894 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002895 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002896
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002897 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2898 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2899 draining = true;
2900
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002901 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002902 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002903 } else {
2904 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002905 }
2906
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002907out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002908 thread__zput(trace->current);
2909
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002910 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002911
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002912 if (!err) {
2913 if (trace->summary)
2914 trace__fprintf_thread_summary(trace, trace->output);
2915
2916 if (trace->show_tool_stats) {
2917 fprintf(trace->output, "Stats:\n "
2918 " vfs_getname : %" PRIu64 "\n"
2919 " proc_getname: %" PRIu64 "\n",
2920 trace->stats.vfs_getname,
2921 trace->stats.proc_getname);
2922 }
2923 }
David Ahernbf2575c2013-10-08 21:26:53 -06002924
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002925out_delete_evlist:
2926 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002927 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002928 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002929 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002930{
2931 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002932
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002933out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002934 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002935 goto out_error;
2936
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002937out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002938 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002939 goto out_error;
2940
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002941out_error_mmap:
2942 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2943 goto out_error;
2944
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002945out_error_open:
2946 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2947
2948out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002949 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302950 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002951
2952out_error_apply_filters:
2953 fprintf(trace->output,
2954 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2955 evsel->filter, perf_evsel__name(evsel), errno,
2956 strerror_r(errno, errbuf, sizeof(errbuf)));
2957 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002958}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002959out_error_mem:
2960 fprintf(trace->output, "Not enough memory to run!\n");
2961 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002962
2963out_errno:
2964 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2965 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002966}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002967
David Ahern6810fc92013-08-28 22:29:52 -06002968static int trace__replay(struct trace *trace)
2969{
2970 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002971 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002972 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002973 struct perf_data_file file = {
2974 .path = input_name,
2975 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002976 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002977 };
David Ahern6810fc92013-08-28 22:29:52 -06002978 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002979 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002980 int err = -1;
2981
2982 trace->tool.sample = trace__process_sample;
2983 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002984 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002985 trace->tool.comm = perf_event__process_comm;
2986 trace->tool.exit = perf_event__process_exit;
2987 trace->tool.fork = perf_event__process_fork;
2988 trace->tool.attr = perf_event__process_attr;
2989 trace->tool.tracing_data = perf_event__process_tracing_data;
2990 trace->tool.build_id = perf_event__process_build_id;
2991
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002992 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002993 trace->tool.ordering_requires_timestamps = true;
2994
2995 /* add tid to output */
2996 trace->multiple_threads = true;
2997
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002998 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002999 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09003000 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06003001
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09003002 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09003003 goto out;
3004
David Ahern8fb598e2013-09-28 13:13:00 -06003005 trace->host = &session->machines.host;
3006
David Ahern6810fc92013-08-28 22:29:52 -06003007 err = perf_session__set_tracepoints_handlers(session, handlers);
3008 if (err)
3009 goto out;
3010
Namhyung Kim003824e2013-11-12 15:25:00 +09003011 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
3012 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07003013 /* older kernels have syscalls tp versus raw_syscalls */
3014 if (evsel == NULL)
3015 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
3016 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06003017
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003018 if (evsel &&
3019 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
3020 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09003021 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
3022 goto out;
3023 }
3024
3025 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
3026 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07003027 if (evsel == NULL)
3028 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
3029 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003030 if (evsel &&
3031 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
3032 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09003033 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06003034 goto out;
3035 }
3036
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003037 evlist__for_each(session->evlist, evsel) {
3038 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
3039 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
3040 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
3041 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
3042 evsel->handler = trace__pgfault;
3043 }
3044
David Ahernbdc89662013-08-28 22:29:53 -06003045 err = parse_target_str(trace);
3046 if (err != 0)
3047 goto out;
3048
David Ahern6810fc92013-08-28 22:29:52 -06003049 setup_pager();
3050
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03003051 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06003052 if (err)
3053 pr_err("Failed to process events, error %d", err);
3054
David Ahernbf2575c2013-10-08 21:26:53 -06003055 else if (trace->summary)
3056 trace__fprintf_thread_summary(trace, trace->output);
3057
David Ahern6810fc92013-08-28 22:29:52 -06003058out:
3059 perf_session__delete(session);
3060
3061 return err;
3062}
3063
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003064static size_t trace__fprintf_threads_header(FILE *fp)
3065{
3066 size_t printed;
3067
Pekka Enberg99ff7152013-11-12 16:42:14 +02003068 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06003069
3070 return printed;
3071}
3072
3073static size_t thread__dump_stats(struct thread_trace *ttrace,
3074 struct trace *trace, FILE *fp)
3075{
3076 struct stats *stats;
3077 size_t printed = 0;
3078 struct syscall *sc;
3079 struct int_node *inode = intlist__first(ttrace->syscall_stats);
3080
3081 if (inode == NULL)
3082 return 0;
3083
3084 printed += fprintf(fp, "\n");
3085
Milian Wolff834fd462015-08-06 11:24:29 +02003086 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
3087 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
3088 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02003089
David Ahernbf2575c2013-10-08 21:26:53 -06003090 /* each int_node is a syscall */
3091 while (inode) {
3092 stats = inode->priv;
3093 if (stats) {
3094 double min = (double)(stats->min) / NSEC_PER_MSEC;
3095 double max = (double)(stats->max) / NSEC_PER_MSEC;
3096 double avg = avg_stats(stats);
3097 double pct;
3098 u64 n = (u64) stats->n;
3099
3100 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
3101 avg /= NSEC_PER_MSEC;
3102
3103 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02003104 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02003105 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
3106 n, avg * n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02003107 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06003108 }
3109
3110 inode = intlist__next(inode);
3111 }
3112
3113 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003114
3115 return printed;
3116}
3117
David Ahern896cbb52013-09-28 13:12:59 -06003118/* struct used to pass data to per-thread function */
3119struct summary_data {
3120 FILE *fp;
3121 struct trace *trace;
3122 size_t printed;
3123};
3124
3125static int trace__fprintf_one_thread(struct thread *thread, void *priv)
3126{
3127 struct summary_data *data = priv;
3128 FILE *fp = data->fp;
3129 size_t printed = data->printed;
3130 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09003131 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06003132 double ratio;
3133
3134 if (ttrace == NULL)
3135 return 0;
3136
3137 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
3138
Pekka Enberg15e65c62013-11-14 18:43:30 +02003139 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003140 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02003141 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04003142 if (ttrace->pfmaj)
3143 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
3144 if (ttrace->pfmin)
3145 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003146 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06003147 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06003148
3149 data->printed += printed;
3150
3151 return 0;
3152}
3153
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003154static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
3155{
David Ahern896cbb52013-09-28 13:12:59 -06003156 struct summary_data data = {
3157 .fp = fp,
3158 .trace = trace
3159 };
3160 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003161
David Ahern896cbb52013-09-28 13:12:59 -06003162 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003163
David Ahern896cbb52013-09-28 13:12:59 -06003164 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003165}
3166
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003167static int trace__set_duration(const struct option *opt, const char *str,
3168 int unset __maybe_unused)
3169{
3170 struct trace *trace = opt->value;
3171
3172 trace->duration_filter = atof(str);
3173 return 0;
3174}
3175
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08003176static int trace__set_filter_pids(const struct option *opt, const char *str,
3177 int unset __maybe_unused)
3178{
3179 int ret = -1;
3180 size_t i;
3181 struct trace *trace = opt->value;
3182 /*
3183 * FIXME: introduce a intarray class, plain parse csv and create a
3184 * { int nr, int entries[] } struct...
3185 */
3186 struct intlist *list = intlist__new(str);
3187
3188 if (list == NULL)
3189 return -1;
3190
3191 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
3192 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
3193
3194 if (trace->filter_pids.entries == NULL)
3195 goto out;
3196
3197 trace->filter_pids.entries[0] = getpid();
3198
3199 for (i = 1; i < trace->filter_pids.nr; ++i)
3200 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
3201
3202 intlist__delete(list);
3203 ret = 0;
3204out:
3205 return ret;
3206}
3207
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003208static int trace__open_output(struct trace *trace, const char *filename)
3209{
3210 struct stat st;
3211
3212 if (!stat(filename, &st) && st.st_size) {
3213 char oldname[PATH_MAX];
3214
3215 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
3216 unlink(oldname);
3217 rename(filename, oldname);
3218 }
3219
3220 trace->output = fopen(filename, "w");
3221
3222 return trace->output == NULL ? -errno : 0;
3223}
3224
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003225static int parse_pagefaults(const struct option *opt, const char *str,
3226 int unset __maybe_unused)
3227{
3228 int *trace_pgfaults = opt->value;
3229
3230 if (strcmp(str, "all") == 0)
3231 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
3232 else if (strcmp(str, "maj") == 0)
3233 *trace_pgfaults |= TRACE_PFMAJ;
3234 else if (strcmp(str, "min") == 0)
3235 *trace_pgfaults |= TRACE_PFMIN;
3236 else
3237 return -1;
3238
3239 return 0;
3240}
3241
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003242static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3243{
3244 struct perf_evsel *evsel;
3245
3246 evlist__for_each(evlist, evsel)
3247 evsel->handler = handler;
3248}
3249
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003250int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3251{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003252 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003253 "perf trace [<options>] [<command>]",
3254 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003255 "perf trace record [<options>] [<command>]",
3256 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003257 NULL
3258 };
3259 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003260 .syscalls = {
3261 . max = -1,
3262 },
3263 .opts = {
3264 .target = {
3265 .uid = UINT_MAX,
3266 .uses_mmap = true,
3267 },
3268 .user_freq = UINT_MAX,
3269 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003270 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003271 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003272 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003273 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003274 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003275 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003276 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003277 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003278 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003279 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003280 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003281 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003282 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3283 "event selector. use 'perf list' to list available events",
3284 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003285 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3286 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003287 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03003288 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003289 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003290 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003291 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3292 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003293 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003294 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003295 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3296 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003297 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003298 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003299 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003300 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003301 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003302 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003303 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3304 "number of mmap data pages",
3305 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003306 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003307 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003308 OPT_CALLBACK(0, "duration", &trace, "float",
3309 "show only events with duration > N.M ms",
3310 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003311 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003312 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003313 OPT_BOOLEAN('T', "time", &trace.full_time,
3314 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003315 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3316 "Show only syscall summary with statistics"),
3317 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3318 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003319 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3320 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003321 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003322 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003323 OPT_CALLBACK(0, "call-graph", &trace.opts,
3324 "record_mode[,record_size]", record_callchain_help,
3325 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003326 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3327 "Show the kernel callchains on the syscall exit path"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003328 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3329 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003330 OPT_END()
3331 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003332 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003333 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003334 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003335
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003336 signal(SIGSEGV, sighandler_dump_stack);
3337 signal(SIGFPE, sighandler_dump_stack);
3338
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003339 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003340 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003341
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003342 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003343 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003344 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003345 goto out;
3346 }
3347
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003348 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3349 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003350
Wang Nand7888572016-04-08 15:07:24 +00003351 err = bpf__setup_stdout(trace.evlist);
3352 if (err) {
3353 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3354 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3355 goto out;
3356 }
3357
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003358 err = -1;
3359
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003360 if (trace.trace_pgfaults) {
3361 trace.opts.sample_address = true;
3362 trace.opts.sample_time = true;
3363 }
3364
Milian Wolff566a0882016-04-08 13:34:15 +02003365 if (trace.opts.callgraph_set)
3366 symbol_conf.use_callchain = true;
3367
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003368 if (trace.evlist->nr_entries > 0)
3369 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3370
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003371 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3372 return trace__record(&trace, argc-1, &argv[1]);
3373
3374 /* summary_only implies summary option, but don't overwrite summary if set */
3375 if (trace.summary_only)
3376 trace.summary = trace.summary_only;
3377
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003378 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3379 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003380 pr_err("Please specify something to trace.\n");
3381 return -1;
3382 }
3383
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003384 if (!trace.trace_syscalls && ev_qualifier_str) {
3385 pr_err("The -e option can't be used with --no-syscalls.\n");
3386 goto out;
3387 }
3388
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003389 if (output_name != NULL) {
3390 err = trace__open_output(&trace, output_name);
3391 if (err < 0) {
3392 perror("failed to create output file");
3393 goto out;
3394 }
3395 }
3396
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003397 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3398
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003399 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003400 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03003401 struct strlist_config slist_config = {
3402 .dirname = system_path(STRACE_GROUPS_DIR),
3403 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003404
3405 trace.not_ev_qualifier = *s == '!';
3406 if (trace.not_ev_qualifier)
3407 ++s;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03003408 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003409 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003410 fputs("Not enough memory to parse event qualifier",
3411 trace.output);
3412 err = -ENOMEM;
3413 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003414 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003415
3416 err = trace__validate_ev_qualifier(&trace);
3417 if (err)
3418 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003419 }
3420
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003421 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003422 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003423 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003424 fprintf(trace.output, "%s", bf);
3425 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003426 }
3427
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003428 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003429 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003430 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003431 fprintf(trace.output, "%s", bf);
3432 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003433 }
3434
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003435 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003436 trace.opts.target.system_wide = true;
3437
David Ahern6810fc92013-08-28 22:29:52 -06003438 if (input_name)
3439 err = trace__replay(&trace);
3440 else
3441 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003442
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003443out_close:
3444 if (output_name != NULL)
3445 fclose(trace.output);
3446out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003447 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003448}