blob: cfa5ce8fdb7bf881151282ef58490b5591eadbf5 [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 Melo997bba82016-03-30 19:43:32 -03001062static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg)
1063{
1064 int op = arg->val;
1065 size_t printed = 0;
1066
1067 switch (op) {
1068#define P_SECCOMP_SET_MODE_OP(n) case SECCOMP_SET_MODE_##n: printed = scnprintf(bf, size, #n); break
1069 P_SECCOMP_SET_MODE_OP(STRICT);
1070 P_SECCOMP_SET_MODE_OP(FILTER);
1071#undef P_SECCOMP_SET_MODE_OP
1072 default: printed = scnprintf(bf, size, "%#x", op); break;
1073 }
1074
1075 return printed;
1076}
1077
1078#define SCA_SECCOMP_OP syscall_arg__scnprintf_seccomp_op
1079
1080static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size,
1081 struct syscall_arg *arg)
1082{
1083 int printed = 0, flags = arg->val;
1084
1085#define P_FLAG(n) \
1086 if (flags & SECCOMP_FILTER_FLAG_##n) { \
1087 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
1088 flags &= ~SECCOMP_FILTER_FLAG_##n; \
1089 }
1090
1091 P_FLAG(TSYNC);
1092#undef P_FLAG
1093
1094 if (flags)
1095 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
1096
1097 return printed;
1098}
1099
1100#define SCA_SECCOMP_FLAGS syscall_arg__scnprintf_seccomp_flags
1101
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -03001102static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
1103 struct syscall_arg *arg)
1104{
1105 int printed = 0, flags = arg->val;
1106
1107#define P_FLAG(n) \
1108 if (flags & GRND_##n) { \
1109 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
1110 flags &= ~GRND_##n; \
1111 }
1112
1113 P_FLAG(RANDOM);
1114 P_FLAG(NONBLOCK);
1115#undef P_FLAG
1116
1117 if (flags)
1118 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
1119
1120 return printed;
1121}
1122
1123#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
1124
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001125#define STRARRAY(arg, name, array) \
1126 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
1127 .arg_parm = { [arg] = &strarray__##array, }
1128
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001129#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001130#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001131#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001132#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001133
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001134static struct syscall_fmt {
1135 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001136 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001137 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001138 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001139 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001140 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001141 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001142 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001143} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -03001144 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001145 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1146 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001147 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -03001148 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001149 { .name = "brk", .hexret = true,
1150 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001151 { .name = "chdir", .errmsg = true,
1152 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1153 { .name = "chmod", .errmsg = true,
1154 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1155 { .name = "chroot", .errmsg = true,
1156 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -06001157 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001158 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001159 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001160 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -03001161 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001162 { .name = "creat", .errmsg = true,
1163 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001164 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001165 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001166 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001167 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001168 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001169 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001170 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -03001171 { .name = "eventfd2", .errmsg = true,
1172 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001173 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001174 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1175 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001176 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001177 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001178 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001179 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001180 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001181 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001182 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001183 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001184 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001185 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1186 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001187 { .name = "fchown", .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 = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001190 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1191 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001192 { .name = "fcntl", .errmsg = true,
1193 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1194 [1] = SCA_STRARRAY, /* cmd */ },
1195 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1196 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001197 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -03001198 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001199 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1200 [1] = SCA_FLOCK, /* cmd */ }, },
1201 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001202 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001203 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001204 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001205 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001206 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1207 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001208 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001209 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001210 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001211 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001212 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001213 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -03001214 { .name = "futex", .errmsg = true,
1215 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001216 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001217 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1218 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001219 { .name = "getdents", .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 = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001222 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001223 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001224 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001225 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001226 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -03001227 { .name = "getrandom", .errmsg = true,
1228 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001229 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001230 { .name = "getxattr", .errmsg = true,
1231 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1232 { .name = "inotify_add_watch", .errmsg = true,
1233 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001234 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001235 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001236#if defined(__i386__) || defined(__x86_64__)
1237/*
1238 * FIXME: Make this available to all arches.
1239 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001240 [1] = SCA_STRHEXARRAY, /* cmd */
1241 [2] = SCA_HEX, /* arg */ },
1242 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001243#else
1244 [2] = SCA_HEX, /* arg */ }, },
1245#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -03001246 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001247 { .name = "kill", .errmsg = true,
1248 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001249 { .name = "lchown", .errmsg = true,
1250 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1251 { .name = "lgetxattr", .errmsg = true,
1252 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001253 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001254 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001255 { .name = "listxattr", .errmsg = true,
1256 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001257 { .name = "llistxattr", .errmsg = true,
1258 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1259 { .name = "lremovexattr", .errmsg = true,
1260 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001261 { .name = "lseek", .errmsg = true,
1262 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1263 [2] = SCA_STRARRAY, /* whence */ },
1264 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001265 { .name = "lsetxattr", .errmsg = true,
1266 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001267 { .name = "lstat", .errmsg = true, .alias = "newlstat",
1268 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001269 { .name = "lsxattr", .errmsg = true,
1270 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001271 { .name = "madvise", .errmsg = true,
1272 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1273 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001274 { .name = "mkdir", .errmsg = true,
1275 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001276 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001277 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1278 [1] = SCA_FILENAME, /* pathname */ }, },
1279 { .name = "mknod", .errmsg = true,
1280 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001281 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001282 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1283 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001284 { .name = "mlock", .errmsg = true,
1285 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1286 { .name = "mlockall", .errmsg = true,
1287 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001288 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001289 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001290 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001291 [3] = SCA_MMAP_FLAGS, /* flags */
1292 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001293 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001294 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1295 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001296 { .name = "mq_unlink", .errmsg = true,
1297 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001298 { .name = "mremap", .hexret = true,
1299 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001300 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001301 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001302 { .name = "munlock", .errmsg = true,
1303 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001304 { .name = "munmap", .errmsg = true,
1305 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001306 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001307 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001308 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001309 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1310 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001311 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001312 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1313 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001314 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001315 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1316 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001317 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001318 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001319 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001320 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001321 { .name = "perf_event_open", .errmsg = true,
1322 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1323 [2] = SCA_INT, /* cpu */
1324 [3] = SCA_FD, /* group_fd */
1325 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001326 { .name = "pipe2", .errmsg = true,
1327 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001328 { .name = "poll", .errmsg = true, .timeout = true, },
1329 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001330 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001331 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001332 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001333 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001334 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001335 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001336 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001337 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001338 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001339 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001340 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001341 { .name = "readlink", .errmsg = true,
1342 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001343 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001344 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1345 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001346 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001347 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001348 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001349 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1350 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001351 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001352 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1353 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001354 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001355 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1356 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001357 { .name = "removexattr", .errmsg = true,
1358 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001359 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001360 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001361 { .name = "rmdir", .errmsg = true,
1362 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001363 { .name = "rt_sigaction", .errmsg = true,
1364 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001365 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001366 { .name = "rt_sigqueueinfo", .errmsg = true,
1367 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1368 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1369 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001370 { .name = "sched_setscheduler", .errmsg = true,
1371 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001372 { .name = "seccomp", .errmsg = true,
1373 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
1374 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001375 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001376 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001377 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1378 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001379 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001380 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1381 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001382 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001383 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1384 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001385 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001386 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001387 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001388 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001389 { .name = "setxattr", .errmsg = true,
1390 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001391 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001392 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001393 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001394 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1395 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001396 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001397 { .name = "socketpair", .errmsg = true,
1398 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1399 [1] = SCA_SK_TYPE, /* type */ },
1400 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001401 { .name = "stat", .errmsg = true, .alias = "newstat",
1402 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001403 { .name = "statfs", .errmsg = true,
1404 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1405 { .name = "swapoff", .errmsg = true,
1406 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1407 { .name = "swapon", .errmsg = true,
1408 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001409 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001410 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001411 { .name = "tgkill", .errmsg = true,
1412 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1413 { .name = "tkill", .errmsg = true,
1414 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001415 { .name = "truncate", .errmsg = true,
1416 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001417 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001418 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001419 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1420 [1] = SCA_FILENAME, /* pathname */ }, },
1421 { .name = "utime", .errmsg = true,
1422 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001423 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001424 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1425 [1] = SCA_FILENAME, /* filename */ }, },
1426 { .name = "utimes", .errmsg = true,
1427 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001428 { .name = "vmsplice", .errmsg = true,
1429 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001430 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001431 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001432 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001433 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001434 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001435 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001436 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001437 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001438};
1439
1440static int syscall_fmt__cmp(const void *name, const void *fmtp)
1441{
1442 const struct syscall_fmt *fmt = fmtp;
1443 return strcmp(name, fmt->name);
1444}
1445
1446static struct syscall_fmt *syscall_fmt__find(const char *name)
1447{
1448 const int nmemb = ARRAY_SIZE(syscall_fmts);
1449 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1450}
1451
1452struct syscall {
1453 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001454 int nr_args;
1455 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001456 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001457 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001458 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001459 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001460 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001461};
1462
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001463static size_t fprintf_duration(unsigned long t, FILE *fp)
1464{
1465 double duration = (double)t / NSEC_PER_MSEC;
1466 size_t printed = fprintf(fp, "(");
1467
1468 if (duration >= 1.0)
1469 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1470 else if (duration >= 0.01)
1471 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1472 else
1473 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001474 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001475}
1476
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001477/**
1478 * filename.ptr: The filename char pointer that will be vfs_getname'd
1479 * filename.entry_str_pos: Where to insert the string translated from
1480 * filename.ptr by the vfs_getname tracepoint/kprobe.
1481 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001482struct thread_trace {
1483 u64 entry_time;
1484 u64 exit_time;
1485 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001486 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001487 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001488 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001489 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001490 struct {
1491 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001492 short int entry_str_pos;
1493 bool pending_open;
1494 unsigned int namelen;
1495 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001496 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001497 struct {
1498 int max;
1499 char **table;
1500 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001501
1502 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001503};
1504
1505static struct thread_trace *thread_trace__new(void)
1506{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001507 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1508
1509 if (ttrace)
1510 ttrace->paths.max = -1;
1511
David Ahernbf2575c2013-10-08 21:26:53 -06001512 ttrace->syscall_stats = intlist__new(NULL);
1513
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001514 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001515}
1516
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001517static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001518{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001519 struct thread_trace *ttrace;
1520
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001521 if (thread == NULL)
1522 goto fail;
1523
Namhyung Kim89dceb22014-10-06 09:46:03 +09001524 if (thread__priv(thread) == NULL)
1525 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001526
Namhyung Kim89dceb22014-10-06 09:46:03 +09001527 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001528 goto fail;
1529
Namhyung Kim89dceb22014-10-06 09:46:03 +09001530 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001531 ++ttrace->nr_events;
1532
1533 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001534fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001535 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001536 "WARNING: not enough memory, dropping samples!\n");
1537 return NULL;
1538}
1539
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001540#define TRACE_PFMAJ (1 << 0)
1541#define TRACE_PFMIN (1 << 1)
1542
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001543static const size_t trace__entry_str_size = 2048;
1544
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001545static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001546{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001547 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001548
1549 if (fd > ttrace->paths.max) {
1550 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1551
1552 if (npath == NULL)
1553 return -1;
1554
1555 if (ttrace->paths.max != -1) {
1556 memset(npath + ttrace->paths.max + 1, 0,
1557 (fd - ttrace->paths.max) * sizeof(char *));
1558 } else {
1559 memset(npath, 0, (fd + 1) * sizeof(char *));
1560 }
1561
1562 ttrace->paths.table = npath;
1563 ttrace->paths.max = fd;
1564 }
1565
1566 ttrace->paths.table[fd] = strdup(pathname);
1567
1568 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1569}
1570
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001571static int thread__read_fd_path(struct thread *thread, int fd)
1572{
1573 char linkname[PATH_MAX], pathname[PATH_MAX];
1574 struct stat st;
1575 int ret;
1576
1577 if (thread->pid_ == thread->tid) {
1578 scnprintf(linkname, sizeof(linkname),
1579 "/proc/%d/fd/%d", thread->pid_, fd);
1580 } else {
1581 scnprintf(linkname, sizeof(linkname),
1582 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1583 }
1584
1585 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1586 return -1;
1587
1588 ret = readlink(linkname, pathname, sizeof(pathname));
1589
1590 if (ret < 0 || ret > st.st_size)
1591 return -1;
1592
1593 pathname[ret] = '\0';
1594 return trace__set_fd_pathname(thread, fd, pathname);
1595}
1596
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001597static const char *thread__fd_path(struct thread *thread, int fd,
1598 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001599{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001600 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001601
1602 if (ttrace == NULL)
1603 return NULL;
1604
1605 if (fd < 0)
1606 return NULL;
1607
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001608 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001609 if (!trace->live)
1610 return NULL;
1611 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001612 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001613 return NULL;
1614 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001615
1616 return ttrace->paths.table[fd];
1617}
1618
1619static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1620 struct syscall_arg *arg)
1621{
1622 int fd = arg->val;
1623 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001624 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001625
1626 if (path)
1627 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1628
1629 return printed;
1630}
1631
1632static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1633 struct syscall_arg *arg)
1634{
1635 int fd = arg->val;
1636 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001637 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001638
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001639 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1640 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001641
1642 return printed;
1643}
1644
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001645static void thread__set_filename_pos(struct thread *thread, const char *bf,
1646 unsigned long ptr)
1647{
1648 struct thread_trace *ttrace = thread__priv(thread);
1649
1650 ttrace->filename.ptr = ptr;
1651 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1652}
1653
1654static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1655 struct syscall_arg *arg)
1656{
1657 unsigned long ptr = arg->val;
1658
1659 if (!arg->trace->vfs_getname)
1660 return scnprintf(bf, size, "%#x", ptr);
1661
1662 thread__set_filename_pos(arg->thread, bf, ptr);
1663 return 0;
1664}
1665
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001666static bool trace__filter_duration(struct trace *trace, double t)
1667{
1668 return t < (trace->duration_filter * NSEC_PER_MSEC);
1669}
1670
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001671static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1672{
1673 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1674
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001675 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001676}
1677
Namhyung Kimf15eb532012-10-05 14:02:16 +09001678static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001679static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001680
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001681static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001682{
1683 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001684 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001685}
1686
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001687static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001688 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001689{
1690 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001691 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001692
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001693 if (trace->multiple_threads) {
1694 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001695 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001696 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001697 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001698
1699 return printed;
1700}
1701
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001702static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001703 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001704{
1705 int ret = 0;
1706
1707 switch (event->header.type) {
1708 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001709 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001710 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001711 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001712 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001713 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001714 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001715 break;
1716 }
1717
1718 return ret;
1719}
1720
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001721static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001722 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001723 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001724 struct machine *machine)
1725{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001726 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001727 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001728}
1729
1730static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1731{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001732 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001733
1734 if (err)
1735 return err;
1736
David Ahern8fb598e2013-09-28 13:13:00 -06001737 trace->host = machine__new_host();
1738 if (trace->host == NULL)
1739 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001740
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001741 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001742 return -errno;
1743
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001744 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001745 evlist->threads, trace__tool_process, false,
1746 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001747 if (err)
1748 symbol__exit();
1749
1750 return err;
1751}
1752
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001753static int syscall__set_arg_fmts(struct syscall *sc)
1754{
1755 struct format_field *field;
1756 int idx = 0;
1757
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001758 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001759 if (sc->arg_scnprintf == NULL)
1760 return -1;
1761
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001762 if (sc->fmt)
1763 sc->arg_parm = sc->fmt->arg_parm;
1764
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001765 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001766 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1767 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1768 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001769 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001770 else if (strcmp(field->type, "pid_t") == 0)
1771 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001772 else if (strcmp(field->type, "umode_t") == 0)
1773 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001774 ++idx;
1775 }
1776
1777 return 0;
1778}
1779
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001780static int trace__read_syscall_info(struct trace *trace, int id)
1781{
1782 char tp_name[128];
1783 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001784 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001785
1786 if (name == NULL)
1787 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001788
1789 if (id > trace->syscalls.max) {
1790 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1791
1792 if (nsyscalls == NULL)
1793 return -1;
1794
1795 if (trace->syscalls.max != -1) {
1796 memset(nsyscalls + trace->syscalls.max + 1, 0,
1797 (id - trace->syscalls.max) * sizeof(*sc));
1798 } else {
1799 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1800 }
1801
1802 trace->syscalls.table = nsyscalls;
1803 trace->syscalls.max = id;
1804 }
1805
1806 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001807 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001808
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001809 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001810
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001811 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001812 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001813
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001814 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001815 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001816 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001817 }
1818
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001819 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001820 return -1;
1821
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001822 sc->args = sc->tp_format->format.fields;
1823 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001824 /*
1825 * We need to check and discard the first variable '__syscall_nr'
1826 * or 'nr' that mean the syscall number. It is needless here.
1827 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1828 */
1829 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001830 sc->args = sc->args->next;
1831 --sc->nr_args;
1832 }
1833
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001834 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1835
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001836 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001837}
1838
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001839static int trace__validate_ev_qualifier(struct trace *trace)
1840{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001841 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001842 struct str_node *pos;
1843
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001844 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1845 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1846 sizeof(trace->ev_qualifier_ids.entries[0]));
1847
1848 if (trace->ev_qualifier_ids.entries == NULL) {
1849 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1850 trace->output);
1851 err = -EINVAL;
1852 goto out;
1853 }
1854
1855 i = 0;
1856
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001857 strlist__for_each(pos, trace->ev_qualifier) {
1858 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001859 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001860
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001861 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001862 if (err == 0) {
1863 fputs("Error:\tInvalid syscall ", trace->output);
1864 err = -EINVAL;
1865 } else {
1866 fputs(", ", trace->output);
1867 }
1868
1869 fputs(sc, trace->output);
1870 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001871
1872 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001873 }
1874
1875 if (err < 0) {
1876 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1877 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001878 zfree(&trace->ev_qualifier_ids.entries);
1879 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001880 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001881out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001882 return err;
1883}
1884
David Ahern55d43bc2015-02-19 15:00:22 -05001885/*
1886 * args is to be interpreted as a series of longs but we need to handle
1887 * 8-byte unaligned accesses. args points to raw_data within the event
1888 * and raw_data is guaranteed to be 8-byte unaligned because it is
1889 * preceded by raw_size which is a u32. So we need to copy args to a temp
1890 * variable to read it. Most notably this avoids extended load instructions
1891 * on unaligned addresses
1892 */
1893
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001894static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001895 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001896 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001897{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001898 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001899 unsigned char *p;
1900 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001901
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001902 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001903 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001904 u8 bit = 1;
1905 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001906 .idx = 0,
1907 .mask = 0,
1908 .trace = trace,
1909 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001910 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001911
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001912 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001913 field = field->next, ++arg.idx, bit <<= 1) {
1914 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001915 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001916
1917 /* special care for unaligned accesses */
1918 p = args + sizeof(unsigned long) * arg.idx;
1919 memcpy(&val, p, sizeof(val));
1920
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001921 /*
1922 * Suppress this argument if its value is zero and
1923 * and we don't have a string associated in an
1924 * strarray for it.
1925 */
David Ahern55d43bc2015-02-19 15:00:22 -05001926 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001927 !(sc->arg_scnprintf &&
1928 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1929 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001930 continue;
1931
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001932 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001933 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001934 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001935 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001936 if (sc->arg_parm)
1937 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001938 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1939 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001940 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001941 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001942 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001943 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001944 }
1945 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001946 int i = 0;
1947
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001948 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001949 /* special care for unaligned accesses */
1950 p = args + sizeof(unsigned long) * i;
1951 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001952 printed += scnprintf(bf + printed, size - printed,
1953 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001954 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001955 ++i;
1956 }
1957 }
1958
1959 return printed;
1960}
1961
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001962typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001963 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001964 struct perf_sample *sample);
1965
1966static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001967 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001968{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001969
1970 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001971
1972 /*
1973 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1974 * before that, leaving at a higher verbosity level till that is
1975 * explained. Reproduced with plain ftrace with:
1976 *
1977 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1978 * grep "NR -1 " /t/trace_pipe
1979 *
1980 * After generating some load on the machine.
1981 */
1982 if (verbose > 1) {
1983 static u64 n;
1984 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1985 id, perf_evsel__name(evsel), ++n);
1986 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001987 return NULL;
1988 }
1989
1990 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1991 trace__read_syscall_info(trace, id))
1992 goto out_cant_read;
1993
1994 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1995 goto out_cant_read;
1996
1997 return &trace->syscalls.table[id];
1998
1999out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002000 if (verbose) {
2001 fprintf(trace->output, "Problems reading syscall %d", id);
2002 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
2003 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
2004 fputs(" information\n", trace->output);
2005 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002006 return NULL;
2007}
2008
David Ahernbf2575c2013-10-08 21:26:53 -06002009static void thread__update_stats(struct thread_trace *ttrace,
2010 int id, struct perf_sample *sample)
2011{
2012 struct int_node *inode;
2013 struct stats *stats;
2014 u64 duration = 0;
2015
2016 inode = intlist__findnew(ttrace->syscall_stats, id);
2017 if (inode == NULL)
2018 return;
2019
2020 stats = inode->priv;
2021 if (stats == NULL) {
2022 stats = malloc(sizeof(struct stats));
2023 if (stats == NULL)
2024 return;
2025 init_stats(stats);
2026 inode->priv = stats;
2027 }
2028
2029 if (ttrace->entry_time && sample->time > ttrace->entry_time)
2030 duration = sample->time - ttrace->entry_time;
2031
2032 update_stats(stats, duration);
2033}
2034
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03002035static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
2036{
2037 struct thread_trace *ttrace;
2038 u64 duration;
2039 size_t printed;
2040
2041 if (trace->current == NULL)
2042 return 0;
2043
2044 ttrace = thread__priv(trace->current);
2045
2046 if (!ttrace->entry_pending)
2047 return 0;
2048
2049 duration = sample->time - ttrace->entry_time;
2050
2051 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
2052 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
2053 ttrace->entry_pending = false;
2054
2055 return printed;
2056}
2057
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002058static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002059 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002060 struct perf_sample *sample)
2061{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002062 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002063 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002064 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002065 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002066 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002067 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002068 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002069
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002070 if (sc == NULL)
2071 return -1;
2072
David Ahern8fb598e2013-09-28 13:13:00 -06002073 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002074 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002075 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002076 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002077
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002078 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002079
2080 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002081 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002082 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002083 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002084 }
2085
David Ahern13f22a22015-03-19 12:23:03 -06002086 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03002087 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03002088
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002089 ttrace->entry_time = sample->time;
2090 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002091 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002092
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002093 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002094 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002095
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03002096 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07002097 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002098 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
2099 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002100 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002101 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002102 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002103 /* See trace__vfs_getname & trace__sys_exit */
2104 ttrace->filename.pending_open = false;
2105 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002106
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002107 if (trace->current != thread) {
2108 thread__put(trace->current);
2109 trace->current = thread__get(thread);
2110 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002111 err = 0;
2112out_put:
2113 thread__put(thread);
2114 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002115}
2116
2117static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002118 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002119 struct perf_sample *sample)
2120{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002121 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002122 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002123 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002124 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002125 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002126 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002127
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002128 if (sc == NULL)
2129 return -1;
2130
David Ahern8fb598e2013-09-28 13:13:00 -06002131 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002132 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002133 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002134 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002135
David Ahernbf2575c2013-10-08 21:26:53 -06002136 if (trace->summary)
2137 thread__update_stats(ttrace, id, sample);
2138
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002139 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002140
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002141 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002142 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
2143 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002144 ++trace->stats.vfs_getname;
2145 }
2146
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002147 ttrace->exit_time = sample->time;
2148
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002149 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002150 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002151 if (trace__filter_duration(trace, duration))
2152 goto out;
2153 } else if (trace->duration_filter)
2154 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002155
David Ahernfd2eaba2013-11-12 09:31:15 -07002156 if (trace->summary_only)
2157 goto out;
2158
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002159 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002160
2161 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002162 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002163 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002164 fprintf(trace->output, " ... [");
2165 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
2166 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002167 }
2168
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002169 if (sc->fmt == NULL) {
2170signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002171 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03002172 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00002173 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002174 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
2175 *e = audit_errno_to_name(-ret);
2176
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002177 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002178 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002179 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03002180 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002181 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03002182 else if (sc->fmt->errpid) {
2183 struct thread *child = machine__find_thread(trace->host, ret, ret);
2184
2185 if (child != NULL) {
2186 fprintf(trace->output, ") = %ld", ret);
2187 if (child->comm_set)
2188 fprintf(trace->output, " (%s)", thread__comm_str(child));
2189 thread__put(child);
2190 }
2191 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002192 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002193
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002194 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02002195
2196 if (sample->callchain) {
2197 struct addr_location al;
2198 /* TODO: user-configurable print_opts */
2199 const unsigned int print_opts = PRINT_IP_OPT_SYM
2200 | PRINT_IP_OPT_DSO;
2201
2202 if (machine__resolve(trace->host, &al, sample) < 0) {
2203 pr_err("problem processing %d event, skipping it.\n",
2204 event->header.type);
2205 goto out_put;
2206 }
Arnaldo Carvalho de Meloea453962016-04-11 12:15:48 -03002207 perf_evsel__fprintf_callchain(evsel, sample, &al, 38, print_opts,
2208 scripting_max_stack, trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02002209 }
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002210out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002211 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002212 err = 0;
2213out_put:
2214 thread__put(thread);
2215 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002216}
2217
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002218static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002219 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002220 struct perf_sample *sample)
2221{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002222 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2223 struct thread_trace *ttrace;
2224 size_t filename_len, entry_str_len, to_move;
2225 ssize_t remaining_space;
2226 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002227 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002228
2229 if (!thread)
2230 goto out;
2231
2232 ttrace = thread__priv(thread);
2233 if (!ttrace)
2234 goto out;
2235
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002236 filename_len = strlen(filename);
2237
2238 if (ttrace->filename.namelen < filename_len) {
2239 char *f = realloc(ttrace->filename.name, filename_len + 1);
2240
2241 if (f == NULL)
2242 goto out;
2243
2244 ttrace->filename.namelen = filename_len;
2245 ttrace->filename.name = f;
2246 }
2247
2248 strcpy(ttrace->filename.name, filename);
2249 ttrace->filename.pending_open = true;
2250
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002251 if (!ttrace->filename.ptr)
2252 goto out;
2253
2254 entry_str_len = strlen(ttrace->entry_str);
2255 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2256 if (remaining_space <= 0)
2257 goto out;
2258
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002259 if (filename_len > (size_t)remaining_space) {
2260 filename += filename_len - remaining_space;
2261 filename_len = remaining_space;
2262 }
2263
2264 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2265 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2266 memmove(pos + filename_len, pos, to_move);
2267 memcpy(pos, filename, filename_len);
2268
2269 ttrace->filename.ptr = 0;
2270 ttrace->filename.entry_str_pos = 0;
2271out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002272 return 0;
2273}
2274
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002275static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002276 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002277 struct perf_sample *sample)
2278{
2279 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2280 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06002281 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03002282 sample->pid,
2283 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002284 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002285
2286 if (ttrace == NULL)
2287 goto out_dump;
2288
2289 ttrace->runtime_ms += runtime_ms;
2290 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002291 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002292 return 0;
2293
2294out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002295 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002296 evsel->name,
2297 perf_evsel__strval(evsel, sample, "comm"),
2298 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2299 runtime,
2300 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002301 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002302 return 0;
2303}
2304
Wang Nan1d6c9402016-02-26 09:31:55 +00002305static void bpf_output__printer(enum binary_printer_ops op,
2306 unsigned int val, void *extra)
2307{
2308 FILE *output = extra;
2309 unsigned char ch = (unsigned char)val;
2310
2311 switch (op) {
2312 case BINARY_PRINT_CHAR_DATA:
2313 fprintf(output, "%c", isprint(ch) ? ch : '.');
2314 break;
2315 case BINARY_PRINT_DATA_BEGIN:
2316 case BINARY_PRINT_LINE_BEGIN:
2317 case BINARY_PRINT_ADDR:
2318 case BINARY_PRINT_NUM_DATA:
2319 case BINARY_PRINT_NUM_PAD:
2320 case BINARY_PRINT_SEP:
2321 case BINARY_PRINT_CHAR_PAD:
2322 case BINARY_PRINT_LINE_END:
2323 case BINARY_PRINT_DATA_END:
2324 default:
2325 break;
2326 }
2327}
2328
2329static void bpf_output__fprintf(struct trace *trace,
2330 struct perf_sample *sample)
2331{
2332 print_binary(sample->raw_data, sample->raw_size, 8,
2333 bpf_output__printer, trace->output);
2334}
2335
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002336static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2337 union perf_event *event __maybe_unused,
2338 struct perf_sample *sample)
2339{
2340 trace__printf_interrupted_entry(trace, sample);
2341 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002342
2343 if (trace->trace_syscalls)
2344 fprintf(trace->output, "( ): ");
2345
2346 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002347
Wang Nan1d6c9402016-02-26 09:31:55 +00002348 if (perf_evsel__is_bpf_output(evsel)) {
2349 bpf_output__fprintf(trace, sample);
2350 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002351 event_format__fprintf(evsel->tp_format, sample->cpu,
2352 sample->raw_data, sample->raw_size,
2353 trace->output);
2354 }
2355
2356 fprintf(trace->output, ")\n");
2357 return 0;
2358}
2359
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002360static void print_location(FILE *f, struct perf_sample *sample,
2361 struct addr_location *al,
2362 bool print_dso, bool print_sym)
2363{
2364
2365 if ((verbose || print_dso) && al->map)
2366 fprintf(f, "%s@", al->map->dso->long_name);
2367
2368 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002369 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002370 al->addr - al->sym->start);
2371 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002372 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002373 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002374 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002375}
2376
2377static int trace__pgfault(struct trace *trace,
2378 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002379 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002380 struct perf_sample *sample)
2381{
2382 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002383 struct addr_location al;
2384 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002385 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002386 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002387
2388 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002389 ttrace = thread__trace(thread, trace->output);
2390 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002391 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002392
2393 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2394 ttrace->pfmaj++;
2395 else
2396 ttrace->pfmin++;
2397
2398 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002399 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002400
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002401 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002402 sample->ip, &al);
2403
2404 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2405
2406 fprintf(trace->output, "%sfault [",
2407 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2408 "maj" : "min");
2409
2410 print_location(trace->output, sample, &al, false, true);
2411
2412 fprintf(trace->output, "] => ");
2413
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002414 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002415 sample->addr, &al);
2416
2417 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002418 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002419 MAP__FUNCTION, sample->addr, &al);
2420
2421 if (al.map)
2422 map_type = 'x';
2423 else
2424 map_type = '?';
2425 }
2426
2427 print_location(trace->output, sample, &al, true, false);
2428
2429 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002430out:
2431 err = 0;
2432out_put:
2433 thread__put(thread);
2434 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002435}
2436
David Ahernbdc89662013-08-28 22:29:53 -06002437static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2438{
2439 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2440 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2441 return false;
2442
2443 if (trace->pid_list || trace->tid_list)
2444 return true;
2445
2446 return false;
2447}
2448
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002449static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002450 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002451 struct perf_sample *sample)
2452{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002453 /*
2454 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2455 * and don't use sample->time unconditionally, we may end up having
2456 * some other event in the future without PERF_SAMPLE_TIME for good
2457 * reason, i.e. we may not be interested in its timestamps, just in
2458 * it taking place, picking some piece of information when it
2459 * appears in our event stream (vfs_getname comes to mind).
2460 */
2461 if (trace->base_time == 0 && !trace->full_time &&
2462 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002463 trace->base_time = sample->time;
2464}
2465
David Ahern6810fc92013-08-28 22:29:52 -06002466static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002467 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002468 struct perf_sample *sample,
2469 struct perf_evsel *evsel,
2470 struct machine *machine __maybe_unused)
2471{
2472 struct trace *trace = container_of(tool, struct trace, tool);
2473 int err = 0;
2474
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002475 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002476
David Ahernbdc89662013-08-28 22:29:53 -06002477 if (skip_sample(trace, sample))
2478 return 0;
2479
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002480 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002481
David Ahern31605652013-12-04 19:41:41 -07002482 if (handler) {
2483 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002484 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002485 }
David Ahern6810fc92013-08-28 22:29:52 -06002486
2487 return err;
2488}
2489
David Ahernbdc89662013-08-28 22:29:53 -06002490static int parse_target_str(struct trace *trace)
2491{
2492 if (trace->opts.target.pid) {
2493 trace->pid_list = intlist__new(trace->opts.target.pid);
2494 if (trace->pid_list == NULL) {
2495 pr_err("Error parsing process id string\n");
2496 return -EINVAL;
2497 }
2498 }
2499
2500 if (trace->opts.target.tid) {
2501 trace->tid_list = intlist__new(trace->opts.target.tid);
2502 if (trace->tid_list == NULL) {
2503 pr_err("Error parsing thread id string\n");
2504 return -EINVAL;
2505 }
2506 }
2507
2508 return 0;
2509}
2510
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002511static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002512{
2513 unsigned int rec_argc, i, j;
2514 const char **rec_argv;
2515 const char * const record_args[] = {
2516 "record",
2517 "-R",
2518 "-m", "1024",
2519 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002520 };
2521
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002522 const char * const sc_args[] = { "-e", };
2523 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2524 const char * const majpf_args[] = { "-e", "major-faults" };
2525 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2526 const char * const minpf_args[] = { "-e", "minor-faults" };
2527 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2528
David Ahern9aca7f12013-12-04 19:41:39 -07002529 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002530 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2531 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002532 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2533
2534 if (rec_argv == NULL)
2535 return -ENOMEM;
2536
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002537 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002538 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002539 rec_argv[j++] = record_args[i];
2540
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002541 if (trace->trace_syscalls) {
2542 for (i = 0; i < sc_args_nr; i++)
2543 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002544
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002545 /* event string may be different for older kernels - e.g., RHEL6 */
2546 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2547 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2548 else if (is_valid_tracepoint("syscalls:sys_enter"))
2549 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2550 else {
2551 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2552 return -1;
2553 }
David Ahern9aca7f12013-12-04 19:41:39 -07002554 }
David Ahern9aca7f12013-12-04 19:41:39 -07002555
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002556 if (trace->trace_pgfaults & TRACE_PFMAJ)
2557 for (i = 0; i < majpf_args_nr; i++)
2558 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002559
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002560 if (trace->trace_pgfaults & TRACE_PFMIN)
2561 for (i = 0; i < minpf_args_nr; i++)
2562 rec_argv[j++] = minpf_args[i];
2563
2564 for (i = 0; i < (unsigned int)argc; i++)
2565 rec_argv[j++] = argv[i];
2566
2567 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002568}
2569
David Ahernbf2575c2013-10-08 21:26:53 -06002570static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2571
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002572static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002573{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002574 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002575
2576 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002577 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002578
2579 if (perf_evsel__field(evsel, "pathname") == NULL) {
2580 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002581 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002582 }
2583
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002584 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002585 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002586 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002587}
2588
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002589static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2590 u64 config)
2591{
2592 struct perf_evsel *evsel;
2593 struct perf_event_attr attr = {
2594 .type = PERF_TYPE_SOFTWARE,
2595 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002596 };
2597
2598 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002599 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002600
2601 event_attr_init(&attr);
2602
2603 evsel = perf_evsel__new(&attr);
2604 if (!evsel)
2605 return -ENOMEM;
2606
2607 evsel->handler = trace__pgfault;
2608 perf_evlist__add(evlist, evsel);
2609
2610 return 0;
2611}
2612
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002613static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2614{
2615 const u32 type = event->header.type;
2616 struct perf_evsel *evsel;
2617
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002618 if (type != PERF_RECORD_SAMPLE) {
2619 trace__process_event(trace, trace->host, event, sample);
2620 return;
2621 }
2622
2623 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2624 if (evsel == NULL) {
2625 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2626 return;
2627 }
2628
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002629 trace__set_base_time(trace, evsel, sample);
2630
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002631 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2632 sample->raw_data == NULL) {
2633 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2634 perf_evsel__name(evsel), sample->tid,
2635 sample->cpu, sample->raw_size);
2636 } else {
2637 tracepoint_handler handler = evsel->handler;
2638 handler(trace, evsel, event, sample);
2639 }
2640}
2641
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002642static int trace__add_syscall_newtp(struct trace *trace)
2643{
2644 int ret = -1;
2645 struct perf_evlist *evlist = trace->evlist;
2646 struct perf_evsel *sys_enter, *sys_exit;
2647
2648 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2649 if (sys_enter == NULL)
2650 goto out;
2651
2652 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2653 goto out_delete_sys_enter;
2654
2655 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2656 if (sys_exit == NULL)
2657 goto out_delete_sys_enter;
2658
2659 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2660 goto out_delete_sys_exit;
2661
2662 perf_evlist__add(evlist, sys_enter);
2663 perf_evlist__add(evlist, sys_exit);
2664
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002665 if (trace->opts.callgraph_set && !trace->kernel_syscallchains) {
2666 /*
2667 * We're interested only in the user space callchain
2668 * leading to the syscall, allow overriding that for
2669 * debugging reasons using --kernel_syscall_callchains
2670 */
2671 sys_exit->attr.exclude_callchain_kernel = 1;
2672 }
2673
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002674 trace->syscalls.events.sys_enter = sys_enter;
2675 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002676
2677 ret = 0;
2678out:
2679 return ret;
2680
2681out_delete_sys_exit:
2682 perf_evsel__delete_priv(sys_exit);
2683out_delete_sys_enter:
2684 perf_evsel__delete_priv(sys_enter);
2685 goto out;
2686}
2687
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002688static int trace__set_ev_qualifier_filter(struct trace *trace)
2689{
2690 int err = -1;
2691 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2692 trace->ev_qualifier_ids.nr,
2693 trace->ev_qualifier_ids.entries);
2694
2695 if (filter == NULL)
2696 goto out_enomem;
2697
2698 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2699 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2700
2701 free(filter);
2702out:
2703 return err;
2704out_enomem:
2705 errno = ENOMEM;
2706 goto out;
2707}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002708
Namhyung Kimf15eb532012-10-05 14:02:16 +09002709static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002710{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002711 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002712 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002713 int err = -1, i;
2714 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002715 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002716 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002717
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002718 trace->live = true;
2719
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002720 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002721 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002722
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002723 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002724 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002725
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002726 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002727 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002728 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002729 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002730
2731 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2732 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002733 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002734
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002735 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002736 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2737 trace__sched_stat_runtime))
2738 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002739
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002740 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2741 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002742 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002743 goto out_delete_evlist;
2744 }
2745
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002746 err = trace__symbols_init(trace, evlist);
2747 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002748 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002749 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002750 }
2751
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002752 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002753
Namhyung Kimf15eb532012-10-05 14:02:16 +09002754 signal(SIGCHLD, sig_handler);
2755 signal(SIGINT, sig_handler);
2756
2757 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002758 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002759 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002760 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002761 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002762 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002763 }
2764 }
2765
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002766 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002767 if (err < 0)
2768 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002769
Wang Nanba504232016-02-26 09:31:54 +00002770 err = bpf__apply_obj_config();
2771 if (err) {
2772 char errbuf[BUFSIZ];
2773
2774 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2775 pr_err("ERROR: Apply config to BPF failed: %s\n",
2776 errbuf);
2777 goto out_error_open;
2778 }
2779
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002780 /*
2781 * Better not use !target__has_task() here because we need to cover the
2782 * case where no threads were specified in the command line, but a
2783 * workload was, and in that case we will fill in the thread_map when
2784 * we fork the workload in perf_evlist__prepare_workload.
2785 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002786 if (trace->filter_pids.nr > 0)
2787 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002788 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002789 err = perf_evlist__set_filter_pid(evlist, getpid());
2790
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002791 if (err < 0)
2792 goto out_error_mem;
2793
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002794 if (trace->ev_qualifier_ids.nr > 0) {
2795 err = trace__set_ev_qualifier_filter(trace);
2796 if (err < 0)
2797 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002798
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002799 pr_debug("event qualifier tracepoint filter: %s\n",
2800 trace->syscalls.events.sys_exit->filter);
2801 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002802
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002803 err = perf_evlist__apply_filters(evlist, &evsel);
2804 if (err < 0)
2805 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002806
Jiri Olsaf8850372013-11-28 17:57:22 +01002807 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002808 if (err < 0)
2809 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002810
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002811 if (!target__none(&trace->opts.target))
2812 perf_evlist__enable(evlist);
2813
Namhyung Kimf15eb532012-10-05 14:02:16 +09002814 if (forks)
2815 perf_evlist__start_workload(evlist);
2816
Jiri Olsae13798c2015-06-23 00:36:02 +02002817 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002818 evlist->threads->nr > 1 ||
2819 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002820again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002821 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002822
2823 for (i = 0; i < evlist->nr_mmaps; i++) {
2824 union perf_event *event;
2825
2826 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002827 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002828
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002829 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002830
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002831 err = perf_evlist__parse_sample(evlist, event, &sample);
2832 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002833 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002834 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002835 }
2836
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002837 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002838next_event:
2839 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002840
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002841 if (interrupted)
2842 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002843
2844 if (done && !draining) {
2845 perf_evlist__disable(evlist);
2846 draining = true;
2847 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002848 }
2849 }
2850
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002851 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002852 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002853
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002854 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2855 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2856 draining = true;
2857
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002858 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002859 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002860 } else {
2861 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002862 }
2863
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002864out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002865 thread__zput(trace->current);
2866
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002867 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002868
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002869 if (!err) {
2870 if (trace->summary)
2871 trace__fprintf_thread_summary(trace, trace->output);
2872
2873 if (trace->show_tool_stats) {
2874 fprintf(trace->output, "Stats:\n "
2875 " vfs_getname : %" PRIu64 "\n"
2876 " proc_getname: %" PRIu64 "\n",
2877 trace->stats.vfs_getname,
2878 trace->stats.proc_getname);
2879 }
2880 }
David Ahernbf2575c2013-10-08 21:26:53 -06002881
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002882out_delete_evlist:
2883 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002884 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002885 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002886 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002887{
2888 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002889
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002890out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002891 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002892 goto out_error;
2893
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002894out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002895 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002896 goto out_error;
2897
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002898out_error_mmap:
2899 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2900 goto out_error;
2901
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002902out_error_open:
2903 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2904
2905out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002906 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302907 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002908
2909out_error_apply_filters:
2910 fprintf(trace->output,
2911 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2912 evsel->filter, perf_evsel__name(evsel), errno,
2913 strerror_r(errno, errbuf, sizeof(errbuf)));
2914 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002915}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002916out_error_mem:
2917 fprintf(trace->output, "Not enough memory to run!\n");
2918 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002919
2920out_errno:
2921 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2922 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002923}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002924
David Ahern6810fc92013-08-28 22:29:52 -06002925static int trace__replay(struct trace *trace)
2926{
2927 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002928 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002929 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002930 struct perf_data_file file = {
2931 .path = input_name,
2932 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002933 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002934 };
David Ahern6810fc92013-08-28 22:29:52 -06002935 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002936 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002937 int err = -1;
2938
2939 trace->tool.sample = trace__process_sample;
2940 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002941 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002942 trace->tool.comm = perf_event__process_comm;
2943 trace->tool.exit = perf_event__process_exit;
2944 trace->tool.fork = perf_event__process_fork;
2945 trace->tool.attr = perf_event__process_attr;
2946 trace->tool.tracing_data = perf_event__process_tracing_data;
2947 trace->tool.build_id = perf_event__process_build_id;
2948
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002949 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002950 trace->tool.ordering_requires_timestamps = true;
2951
2952 /* add tid to output */
2953 trace->multiple_threads = true;
2954
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002955 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002956 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002957 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002958
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002959 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002960 goto out;
2961
David Ahern8fb598e2013-09-28 13:13:00 -06002962 trace->host = &session->machines.host;
2963
David Ahern6810fc92013-08-28 22:29:52 -06002964 err = perf_session__set_tracepoints_handlers(session, handlers);
2965 if (err)
2966 goto out;
2967
Namhyung Kim003824e2013-11-12 15:25:00 +09002968 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2969 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002970 /* older kernels have syscalls tp versus raw_syscalls */
2971 if (evsel == NULL)
2972 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2973 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002974
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002975 if (evsel &&
2976 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2977 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002978 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2979 goto out;
2980 }
2981
2982 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2983 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002984 if (evsel == NULL)
2985 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2986 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002987 if (evsel &&
2988 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2989 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002990 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002991 goto out;
2992 }
2993
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002994 evlist__for_each(session->evlist, evsel) {
2995 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2996 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2997 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2998 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2999 evsel->handler = trace__pgfault;
3000 }
3001
David Ahernbdc89662013-08-28 22:29:53 -06003002 err = parse_target_str(trace);
3003 if (err != 0)
3004 goto out;
3005
David Ahern6810fc92013-08-28 22:29:52 -06003006 setup_pager();
3007
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03003008 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06003009 if (err)
3010 pr_err("Failed to process events, error %d", err);
3011
David Ahernbf2575c2013-10-08 21:26:53 -06003012 else if (trace->summary)
3013 trace__fprintf_thread_summary(trace, trace->output);
3014
David Ahern6810fc92013-08-28 22:29:52 -06003015out:
3016 perf_session__delete(session);
3017
3018 return err;
3019}
3020
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003021static size_t trace__fprintf_threads_header(FILE *fp)
3022{
3023 size_t printed;
3024
Pekka Enberg99ff7152013-11-12 16:42:14 +02003025 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06003026
3027 return printed;
3028}
3029
3030static size_t thread__dump_stats(struct thread_trace *ttrace,
3031 struct trace *trace, FILE *fp)
3032{
3033 struct stats *stats;
3034 size_t printed = 0;
3035 struct syscall *sc;
3036 struct int_node *inode = intlist__first(ttrace->syscall_stats);
3037
3038 if (inode == NULL)
3039 return 0;
3040
3041 printed += fprintf(fp, "\n");
3042
Milian Wolff834fd462015-08-06 11:24:29 +02003043 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
3044 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
3045 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02003046
David Ahernbf2575c2013-10-08 21:26:53 -06003047 /* each int_node is a syscall */
3048 while (inode) {
3049 stats = inode->priv;
3050 if (stats) {
3051 double min = (double)(stats->min) / NSEC_PER_MSEC;
3052 double max = (double)(stats->max) / NSEC_PER_MSEC;
3053 double avg = avg_stats(stats);
3054 double pct;
3055 u64 n = (u64) stats->n;
3056
3057 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
3058 avg /= NSEC_PER_MSEC;
3059
3060 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02003061 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02003062 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
3063 n, avg * n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02003064 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06003065 }
3066
3067 inode = intlist__next(inode);
3068 }
3069
3070 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003071
3072 return printed;
3073}
3074
David Ahern896cbb52013-09-28 13:12:59 -06003075/* struct used to pass data to per-thread function */
3076struct summary_data {
3077 FILE *fp;
3078 struct trace *trace;
3079 size_t printed;
3080};
3081
3082static int trace__fprintf_one_thread(struct thread *thread, void *priv)
3083{
3084 struct summary_data *data = priv;
3085 FILE *fp = data->fp;
3086 size_t printed = data->printed;
3087 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09003088 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06003089 double ratio;
3090
3091 if (ttrace == NULL)
3092 return 0;
3093
3094 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
3095
Pekka Enberg15e65c62013-11-14 18:43:30 +02003096 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003097 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02003098 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04003099 if (ttrace->pfmaj)
3100 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
3101 if (ttrace->pfmin)
3102 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003103 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06003104 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06003105
3106 data->printed += printed;
3107
3108 return 0;
3109}
3110
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003111static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
3112{
David Ahern896cbb52013-09-28 13:12:59 -06003113 struct summary_data data = {
3114 .fp = fp,
3115 .trace = trace
3116 };
3117 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003118
David Ahern896cbb52013-09-28 13:12:59 -06003119 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003120
David Ahern896cbb52013-09-28 13:12:59 -06003121 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003122}
3123
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003124static int trace__set_duration(const struct option *opt, const char *str,
3125 int unset __maybe_unused)
3126{
3127 struct trace *trace = opt->value;
3128
3129 trace->duration_filter = atof(str);
3130 return 0;
3131}
3132
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08003133static int trace__set_filter_pids(const struct option *opt, const char *str,
3134 int unset __maybe_unused)
3135{
3136 int ret = -1;
3137 size_t i;
3138 struct trace *trace = opt->value;
3139 /*
3140 * FIXME: introduce a intarray class, plain parse csv and create a
3141 * { int nr, int entries[] } struct...
3142 */
3143 struct intlist *list = intlist__new(str);
3144
3145 if (list == NULL)
3146 return -1;
3147
3148 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
3149 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
3150
3151 if (trace->filter_pids.entries == NULL)
3152 goto out;
3153
3154 trace->filter_pids.entries[0] = getpid();
3155
3156 for (i = 1; i < trace->filter_pids.nr; ++i)
3157 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
3158
3159 intlist__delete(list);
3160 ret = 0;
3161out:
3162 return ret;
3163}
3164
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003165static int trace__open_output(struct trace *trace, const char *filename)
3166{
3167 struct stat st;
3168
3169 if (!stat(filename, &st) && st.st_size) {
3170 char oldname[PATH_MAX];
3171
3172 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
3173 unlink(oldname);
3174 rename(filename, oldname);
3175 }
3176
3177 trace->output = fopen(filename, "w");
3178
3179 return trace->output == NULL ? -errno : 0;
3180}
3181
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003182static int parse_pagefaults(const struct option *opt, const char *str,
3183 int unset __maybe_unused)
3184{
3185 int *trace_pgfaults = opt->value;
3186
3187 if (strcmp(str, "all") == 0)
3188 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
3189 else if (strcmp(str, "maj") == 0)
3190 *trace_pgfaults |= TRACE_PFMAJ;
3191 else if (strcmp(str, "min") == 0)
3192 *trace_pgfaults |= TRACE_PFMIN;
3193 else
3194 return -1;
3195
3196 return 0;
3197}
3198
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003199static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3200{
3201 struct perf_evsel *evsel;
3202
3203 evlist__for_each(evlist, evsel)
3204 evsel->handler = handler;
3205}
3206
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003207int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3208{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003209 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003210 "perf trace [<options>] [<command>]",
3211 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003212 "perf trace record [<options>] [<command>]",
3213 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003214 NULL
3215 };
3216 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003217 .syscalls = {
3218 . max = -1,
3219 },
3220 .opts = {
3221 .target = {
3222 .uid = UINT_MAX,
3223 .uses_mmap = true,
3224 },
3225 .user_freq = UINT_MAX,
3226 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003227 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003228 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003229 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003230 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003231 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003232 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003233 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003234 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003235 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003236 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003237 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003238 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003239 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3240 "event selector. use 'perf list' to list available events",
3241 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003242 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3243 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003244 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03003245 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003246 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003247 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003248 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3249 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003250 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003251 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003252 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3253 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003254 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003255 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003256 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003257 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003258 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003259 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003260 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3261 "number of mmap data pages",
3262 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003263 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003264 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003265 OPT_CALLBACK(0, "duration", &trace, "float",
3266 "show only events with duration > N.M ms",
3267 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003268 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003269 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003270 OPT_BOOLEAN('T', "time", &trace.full_time,
3271 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003272 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3273 "Show only syscall summary with statistics"),
3274 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3275 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003276 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3277 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003278 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003279 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003280 OPT_CALLBACK(0, "call-graph", &trace.opts,
3281 "record_mode[,record_size]", record_callchain_help,
3282 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003283 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3284 "Show the kernel callchains on the syscall exit path"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003285 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3286 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003287 OPT_END()
3288 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003289 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003290 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003291 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003292
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003293 signal(SIGSEGV, sighandler_dump_stack);
3294 signal(SIGFPE, sighandler_dump_stack);
3295
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003296 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003297 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003298
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003299 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003300 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003301 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003302 goto out;
3303 }
3304
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003305 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3306 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003307
Wang Nand7888572016-04-08 15:07:24 +00003308 err = bpf__setup_stdout(trace.evlist);
3309 if (err) {
3310 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3311 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3312 goto out;
3313 }
3314
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003315 if (trace.trace_pgfaults) {
3316 trace.opts.sample_address = true;
3317 trace.opts.sample_time = true;
3318 }
3319
Milian Wolff566a0882016-04-08 13:34:15 +02003320 if (trace.opts.callgraph_set)
3321 symbol_conf.use_callchain = true;
3322
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003323 if (trace.evlist->nr_entries > 0)
3324 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3325
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003326 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3327 return trace__record(&trace, argc-1, &argv[1]);
3328
3329 /* summary_only implies summary option, but don't overwrite summary if set */
3330 if (trace.summary_only)
3331 trace.summary = trace.summary_only;
3332
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003333 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3334 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003335 pr_err("Please specify something to trace.\n");
3336 return -1;
3337 }
3338
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003339 if (output_name != NULL) {
3340 err = trace__open_output(&trace, output_name);
3341 if (err < 0) {
3342 perror("failed to create output file");
3343 goto out;
3344 }
3345 }
3346
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003347 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3348
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003349 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003350 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003351 struct strlist_config slist_config = {
3352 .dirname = system_path(STRACE_GROUPS_DIR),
3353 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003354
3355 trace.not_ev_qualifier = *s == '!';
3356 if (trace.not_ev_qualifier)
3357 ++s;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003358 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003359 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003360 fputs("Not enough memory to parse event qualifier",
3361 trace.output);
3362 err = -ENOMEM;
3363 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003364 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003365
3366 err = trace__validate_ev_qualifier(&trace);
3367 if (err)
3368 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003369 }
3370
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003371 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003372 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003373 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003374 fprintf(trace.output, "%s", bf);
3375 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003376 }
3377
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003378 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003379 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003380 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003381 fprintf(trace.output, "%s", bf);
3382 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003383 }
3384
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003385 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003386 trace.opts.target.system_wide = true;
3387
David Ahern6810fc92013-08-28 22:29:52 -06003388 if (input_name)
3389 err = trace__replay(&trace);
3390 else
3391 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003392
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003393out_close:
3394 if (output_name != NULL)
3395 fclose(trace.output);
3396out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003397 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003398}