blob: 8440e2b92c6c42d7c88d72bf67a19eac685bccb4 [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"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030037
38#include <libaudit.h>
39#include <stdlib.h>
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030040#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030041#include <linux/futex.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020042#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030043#include <linux/seccomp.h>
44#include <linux/filter.h>
45#include <linux/audit.h>
46#include <sys/ptrace.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030047#include <linux/random.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030048
Ingo Molnar456857b2013-09-12 15:29:00 +020049/* For older distros: */
50#ifndef MAP_STACK
51# define MAP_STACK 0x20000
52#endif
53
54#ifndef MADV_HWPOISON
55# define MADV_HWPOISON 100
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -030056
Ingo Molnar456857b2013-09-12 15:29:00 +020057#endif
58
59#ifndef MADV_MERGEABLE
60# define MADV_MERGEABLE 12
61#endif
62
63#ifndef MADV_UNMERGEABLE
64# define MADV_UNMERGEABLE 13
65#endif
66
Ben Hutchings79d26a62014-02-06 01:00:35 +000067#ifndef EFD_SEMAPHORE
68# define EFD_SEMAPHORE 1
69#endif
70
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030071#ifndef EFD_NONBLOCK
72# define EFD_NONBLOCK 00004000
73#endif
74
75#ifndef EFD_CLOEXEC
76# define EFD_CLOEXEC 02000000
77#endif
78
79#ifndef O_CLOEXEC
80# define O_CLOEXEC 02000000
81#endif
82
83#ifndef SOCK_DCCP
84# define SOCK_DCCP 6
85#endif
86
87#ifndef SOCK_CLOEXEC
88# define SOCK_CLOEXEC 02000000
89#endif
90
91#ifndef SOCK_NONBLOCK
92# define SOCK_NONBLOCK 00004000
93#endif
94
95#ifndef MSG_CMSG_CLOEXEC
96# define MSG_CMSG_CLOEXEC 0x40000000
97#endif
98
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -030099#ifndef PERF_FLAG_FD_NO_GROUP
100# define PERF_FLAG_FD_NO_GROUP (1UL << 0)
101#endif
102
103#ifndef PERF_FLAG_FD_OUTPUT
104# define PERF_FLAG_FD_OUTPUT (1UL << 1)
105#endif
106
107#ifndef PERF_FLAG_PID_CGROUP
108# define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */
109#endif
110
111#ifndef PERF_FLAG_FD_CLOEXEC
112# define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */
113#endif
114
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300115struct trace {
116 struct perf_tool tool;
117 struct {
118 int machine;
119 int open_id;
120 } audit;
121 struct {
122 int max;
123 struct syscall *table;
124 struct {
125 struct perf_evsel *sys_enter,
126 *sys_exit;
127 } events;
128 } syscalls;
129 struct record_opts opts;
130 struct perf_evlist *evlist;
131 struct machine *host;
132 struct thread *current;
133 u64 base_time;
134 FILE *output;
135 unsigned long nr_events;
136 struct strlist *ev_qualifier;
137 struct {
138 size_t nr;
139 int *entries;
140 } ev_qualifier_ids;
141 struct intlist *tid_list;
142 struct intlist *pid_list;
143 struct {
144 size_t nr;
145 pid_t *entries;
146 } filter_pids;
147 double duration_filter;
148 double runtime_ms;
149 struct {
150 u64 vfs_getname,
151 proc_getname;
152 } stats;
153 bool not_ev_qualifier;
154 bool live;
155 bool full_time;
156 bool sched;
157 bool multiple_threads;
158 bool summary;
159 bool summary_only;
160 bool show_comm;
161 bool show_tool_stats;
162 bool trace_syscalls;
163 bool force;
164 bool vfs_getname;
165 int trace_pgfaults;
166};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300167
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300168struct tp_field {
169 int offset;
170 union {
171 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
172 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
173 };
174};
175
176#define TP_UINT_FIELD(bits) \
177static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
178{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500179 u##bits value; \
180 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
181 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300182}
183
184TP_UINT_FIELD(8);
185TP_UINT_FIELD(16);
186TP_UINT_FIELD(32);
187TP_UINT_FIELD(64);
188
189#define TP_UINT_FIELD__SWAPPED(bits) \
190static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
191{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500192 u##bits value; \
193 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300194 return bswap_##bits(value);\
195}
196
197TP_UINT_FIELD__SWAPPED(16);
198TP_UINT_FIELD__SWAPPED(32);
199TP_UINT_FIELD__SWAPPED(64);
200
201static int tp_field__init_uint(struct tp_field *field,
202 struct format_field *format_field,
203 bool needs_swap)
204{
205 field->offset = format_field->offset;
206
207 switch (format_field->size) {
208 case 1:
209 field->integer = tp_field__u8;
210 break;
211 case 2:
212 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
213 break;
214 case 4:
215 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
216 break;
217 case 8:
218 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
219 break;
220 default:
221 return -1;
222 }
223
224 return 0;
225}
226
227static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
228{
229 return sample->raw_data + field->offset;
230}
231
232static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
233{
234 field->offset = format_field->offset;
235 field->pointer = tp_field__ptr;
236 return 0;
237}
238
239struct syscall_tp {
240 struct tp_field id;
241 union {
242 struct tp_field args, ret;
243 };
244};
245
246static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
247 struct tp_field *field,
248 const char *name)
249{
250 struct format_field *format_field = perf_evsel__field(evsel, name);
251
252 if (format_field == NULL)
253 return -1;
254
255 return tp_field__init_uint(field, format_field, evsel->needs_swap);
256}
257
258#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
259 ({ struct syscall_tp *sc = evsel->priv;\
260 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
261
262static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
263 struct tp_field *field,
264 const char *name)
265{
266 struct format_field *format_field = perf_evsel__field(evsel, name);
267
268 if (format_field == NULL)
269 return -1;
270
271 return tp_field__init_ptr(field, format_field);
272}
273
274#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
275 ({ struct syscall_tp *sc = evsel->priv;\
276 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
277
278static void perf_evsel__delete_priv(struct perf_evsel *evsel)
279{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300280 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300281 perf_evsel__delete(evsel);
282}
283
Namhyung Kim96695d42013-11-12 08:51:45 -0300284static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
285{
286 evsel->priv = malloc(sizeof(struct syscall_tp));
287 if (evsel->priv != NULL) {
288 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
289 goto out_delete;
290
291 evsel->handler = handler;
292 return 0;
293 }
294
295 return -ENOMEM;
296
297out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300298 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300299 return -ENOENT;
300}
301
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300302static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300303{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300304 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300305
David Ahern9aca7f12013-12-04 19:41:39 -0700306 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200307 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700308 evsel = perf_evsel__newtp("syscalls", direction);
309
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200310 if (IS_ERR(evsel))
311 return NULL;
312
313 if (perf_evsel__init_syscall_tp(evsel, handler))
314 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300315
316 return evsel;
317
318out_delete:
319 perf_evsel__delete_priv(evsel);
320 return NULL;
321}
322
323#define perf_evsel__sc_tp_uint(evsel, name, sample) \
324 ({ struct syscall_tp *fields = evsel->priv; \
325 fields->name.integer(&fields->name, sample); })
326
327#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
328 ({ struct syscall_tp *fields = evsel->priv; \
329 fields->name.pointer(&fields->name, sample); })
330
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300331struct syscall_arg {
332 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300333 struct thread *thread;
334 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300335 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300336 u8 idx;
337 u8 mask;
338};
339
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300340struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300341 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300342 int nr_entries;
343 const char **entries;
344};
345
346#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
347 .nr_entries = ARRAY_SIZE(array), \
348 .entries = array, \
349}
350
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300351#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
352 .offset = off, \
353 .nr_entries = ARRAY_SIZE(array), \
354 .entries = array, \
355}
356
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300357static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
358 const char *intfmt,
359 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300360{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300361 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300362 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300363
364 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300365 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300366
367 return scnprintf(bf, size, "%s", sa->entries[idx]);
368}
369
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300370static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
371 struct syscall_arg *arg)
372{
373 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
374}
375
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300376#define SCA_STRARRAY syscall_arg__scnprintf_strarray
377
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300378#if defined(__i386__) || defined(__x86_64__)
379/*
380 * FIXME: Make this available to all arches as soon as the ioctl beautifier
381 * gets rewritten to support all arches.
382 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300383static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
384 struct syscall_arg *arg)
385{
386 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
387}
388
389#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300390#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300391
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300392static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
393 struct syscall_arg *arg);
394
395#define SCA_FD syscall_arg__scnprintf_fd
396
397static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
398 struct syscall_arg *arg)
399{
400 int fd = arg->val;
401
402 if (fd == AT_FDCWD)
403 return scnprintf(bf, size, "CWD");
404
405 return syscall_arg__scnprintf_fd(bf, size, arg);
406}
407
408#define SCA_FDAT syscall_arg__scnprintf_fd_at
409
410static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
411 struct syscall_arg *arg);
412
413#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
414
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300415static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300416 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300417{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300418 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300419}
420
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300421#define SCA_HEX syscall_arg__scnprintf_hex
422
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300423static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
424 struct syscall_arg *arg)
425{
426 return scnprintf(bf, size, "%d", arg->val);
427}
428
429#define SCA_INT syscall_arg__scnprintf_int
430
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300431static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300432 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300433{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300434 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300435
436 if (prot == PROT_NONE)
437 return scnprintf(bf, size, "NONE");
438#define P_MMAP_PROT(n) \
439 if (prot & PROT_##n) { \
440 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
441 prot &= ~PROT_##n; \
442 }
443
444 P_MMAP_PROT(EXEC);
445 P_MMAP_PROT(READ);
446 P_MMAP_PROT(WRITE);
447#ifdef PROT_SEM
448 P_MMAP_PROT(SEM);
449#endif
450 P_MMAP_PROT(GROWSDOWN);
451 P_MMAP_PROT(GROWSUP);
452#undef P_MMAP_PROT
453
454 if (prot)
455 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
456
457 return printed;
458}
459
460#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
461
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300462static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300463 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300464{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300465 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300466
467#define P_MMAP_FLAG(n) \
468 if (flags & MAP_##n) { \
469 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
470 flags &= ~MAP_##n; \
471 }
472
473 P_MMAP_FLAG(SHARED);
474 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400475#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300476 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400477#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300478 P_MMAP_FLAG(ANONYMOUS);
479 P_MMAP_FLAG(DENYWRITE);
480 P_MMAP_FLAG(EXECUTABLE);
481 P_MMAP_FLAG(FILE);
482 P_MMAP_FLAG(FIXED);
483 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600484#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300485 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600486#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300487 P_MMAP_FLAG(LOCKED);
488 P_MMAP_FLAG(NONBLOCK);
489 P_MMAP_FLAG(NORESERVE);
490 P_MMAP_FLAG(POPULATE);
491 P_MMAP_FLAG(STACK);
492#ifdef MAP_UNINITIALIZED
493 P_MMAP_FLAG(UNINITIALIZED);
494#endif
495#undef P_MMAP_FLAG
496
497 if (flags)
498 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
499
500 return printed;
501}
502
503#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
504
Alex Snast86998dd2014-08-13 18:42:40 +0300505static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
506 struct syscall_arg *arg)
507{
508 int printed = 0, flags = arg->val;
509
510#define P_MREMAP_FLAG(n) \
511 if (flags & MREMAP_##n) { \
512 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
513 flags &= ~MREMAP_##n; \
514 }
515
516 P_MREMAP_FLAG(MAYMOVE);
517#ifdef MREMAP_FIXED
518 P_MREMAP_FLAG(FIXED);
519#endif
520#undef P_MREMAP_FLAG
521
522 if (flags)
523 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
524
525 return printed;
526}
527
528#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
529
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300530static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300531 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300532{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300533 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300534
535 switch (behavior) {
536#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
537 P_MADV_BHV(NORMAL);
538 P_MADV_BHV(RANDOM);
539 P_MADV_BHV(SEQUENTIAL);
540 P_MADV_BHV(WILLNEED);
541 P_MADV_BHV(DONTNEED);
542 P_MADV_BHV(REMOVE);
543 P_MADV_BHV(DONTFORK);
544 P_MADV_BHV(DOFORK);
545 P_MADV_BHV(HWPOISON);
546#ifdef MADV_SOFT_OFFLINE
547 P_MADV_BHV(SOFT_OFFLINE);
548#endif
549 P_MADV_BHV(MERGEABLE);
550 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600551#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300552 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600553#endif
554#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300555 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600556#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300557#ifdef MADV_DONTDUMP
558 P_MADV_BHV(DONTDUMP);
559#endif
560#ifdef MADV_DODUMP
561 P_MADV_BHV(DODUMP);
562#endif
563#undef P_MADV_PHV
564 default: break;
565 }
566
567 return scnprintf(bf, size, "%#x", behavior);
568}
569
570#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
571
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300572static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
573 struct syscall_arg *arg)
574{
575 int printed = 0, op = arg->val;
576
577 if (op == 0)
578 return scnprintf(bf, size, "NONE");
579#define P_CMD(cmd) \
580 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
581 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
582 op &= ~LOCK_##cmd; \
583 }
584
585 P_CMD(SH);
586 P_CMD(EX);
587 P_CMD(NB);
588 P_CMD(UN);
589 P_CMD(MAND);
590 P_CMD(RW);
591 P_CMD(READ);
592 P_CMD(WRITE);
593#undef P_OP
594
595 if (op)
596 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
597
598 return printed;
599}
600
601#define SCA_FLOCK syscall_arg__scnprintf_flock
602
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300603static 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 -0300604{
605 enum syscall_futex_args {
606 SCF_UADDR = (1 << 0),
607 SCF_OP = (1 << 1),
608 SCF_VAL = (1 << 2),
609 SCF_TIMEOUT = (1 << 3),
610 SCF_UADDR2 = (1 << 4),
611 SCF_VAL3 = (1 << 5),
612 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300613 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300614 int cmd = op & FUTEX_CMD_MASK;
615 size_t printed = 0;
616
617 switch (cmd) {
618#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300619 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
620 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
621 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
622 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
623 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
624 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300625 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300626 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
627 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
628 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
629 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
630 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300631 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
632 default: printed = scnprintf(bf, size, "%#x", cmd); break;
633 }
634
635 if (op & FUTEX_PRIVATE_FLAG)
636 printed += scnprintf(bf + printed, size - printed, "|PRIV");
637
638 if (op & FUTEX_CLOCK_REALTIME)
639 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
640
641 return printed;
642}
643
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300644#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
645
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300646static const char *bpf_cmd[] = {
647 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
648 "MAP_GET_NEXT_KEY", "PROG_LOAD",
649};
650static DEFINE_STRARRAY(bpf_cmd);
651
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300652static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
653static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300654
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300655static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
656static DEFINE_STRARRAY(itimers);
657
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300658static const char *keyctl_options[] = {
659 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
660 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
661 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
662 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
663 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
664};
665static DEFINE_STRARRAY(keyctl_options);
666
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300667static const char *whences[] = { "SET", "CUR", "END",
668#ifdef SEEK_DATA
669"DATA",
670#endif
671#ifdef SEEK_HOLE
672"HOLE",
673#endif
674};
675static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300676
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300677static const char *fcntl_cmds[] = {
678 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
679 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
680 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
681 "F_GETOWNER_UIDS",
682};
683static DEFINE_STRARRAY(fcntl_cmds);
684
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300685static const char *rlimit_resources[] = {
686 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
687 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
688 "RTTIME",
689};
690static DEFINE_STRARRAY(rlimit_resources);
691
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300692static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
693static DEFINE_STRARRAY(sighow);
694
David Ahern4f8c1b72013-09-22 19:45:00 -0600695static const char *clockid[] = {
696 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300697 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
698 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600699};
700static DEFINE_STRARRAY(clockid);
701
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300702static const char *socket_families[] = {
703 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
704 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
705 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
706 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
707 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
708 "ALG", "NFC", "VSOCK",
709};
710static DEFINE_STRARRAY(socket_families);
711
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300712#ifndef SOCK_TYPE_MASK
713#define SOCK_TYPE_MASK 0xf
714#endif
715
716static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
717 struct syscall_arg *arg)
718{
719 size_t printed;
720 int type = arg->val,
721 flags = type & ~SOCK_TYPE_MASK;
722
723 type &= SOCK_TYPE_MASK;
724 /*
725 * Can't use a strarray, MIPS may override for ABI reasons.
726 */
727 switch (type) {
728#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
729 P_SK_TYPE(STREAM);
730 P_SK_TYPE(DGRAM);
731 P_SK_TYPE(RAW);
732 P_SK_TYPE(RDM);
733 P_SK_TYPE(SEQPACKET);
734 P_SK_TYPE(DCCP);
735 P_SK_TYPE(PACKET);
736#undef P_SK_TYPE
737 default:
738 printed = scnprintf(bf, size, "%#x", type);
739 }
740
741#define P_SK_FLAG(n) \
742 if (flags & SOCK_##n) { \
743 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
744 flags &= ~SOCK_##n; \
745 }
746
747 P_SK_FLAG(CLOEXEC);
748 P_SK_FLAG(NONBLOCK);
749#undef P_SK_FLAG
750
751 if (flags)
752 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
753
754 return printed;
755}
756
757#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
758
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300759#ifndef MSG_PROBE
760#define MSG_PROBE 0x10
761#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600762#ifndef MSG_WAITFORONE
763#define MSG_WAITFORONE 0x10000
764#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300765#ifndef MSG_SENDPAGE_NOTLAST
766#define MSG_SENDPAGE_NOTLAST 0x20000
767#endif
768#ifndef MSG_FASTOPEN
769#define MSG_FASTOPEN 0x20000000
770#endif
771
772static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
773 struct syscall_arg *arg)
774{
775 int printed = 0, flags = arg->val;
776
777 if (flags == 0)
778 return scnprintf(bf, size, "NONE");
779#define P_MSG_FLAG(n) \
780 if (flags & MSG_##n) { \
781 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
782 flags &= ~MSG_##n; \
783 }
784
785 P_MSG_FLAG(OOB);
786 P_MSG_FLAG(PEEK);
787 P_MSG_FLAG(DONTROUTE);
788 P_MSG_FLAG(TRYHARD);
789 P_MSG_FLAG(CTRUNC);
790 P_MSG_FLAG(PROBE);
791 P_MSG_FLAG(TRUNC);
792 P_MSG_FLAG(DONTWAIT);
793 P_MSG_FLAG(EOR);
794 P_MSG_FLAG(WAITALL);
795 P_MSG_FLAG(FIN);
796 P_MSG_FLAG(SYN);
797 P_MSG_FLAG(CONFIRM);
798 P_MSG_FLAG(RST);
799 P_MSG_FLAG(ERRQUEUE);
800 P_MSG_FLAG(NOSIGNAL);
801 P_MSG_FLAG(MORE);
802 P_MSG_FLAG(WAITFORONE);
803 P_MSG_FLAG(SENDPAGE_NOTLAST);
804 P_MSG_FLAG(FASTOPEN);
805 P_MSG_FLAG(CMSG_CLOEXEC);
806#undef P_MSG_FLAG
807
808 if (flags)
809 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
810
811 return printed;
812}
813
814#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
815
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300816static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
817 struct syscall_arg *arg)
818{
819 size_t printed = 0;
820 int mode = arg->val;
821
822 if (mode == F_OK) /* 0 */
823 return scnprintf(bf, size, "F");
824#define P_MODE(n) \
825 if (mode & n##_OK) { \
826 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
827 mode &= ~n##_OK; \
828 }
829
830 P_MODE(R);
831 P_MODE(W);
832 P_MODE(X);
833#undef P_MODE
834
835 if (mode)
836 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
837
838 return printed;
839}
840
841#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
842
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300843static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
844 struct syscall_arg *arg);
845
846#define SCA_FILENAME syscall_arg__scnprintf_filename
847
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300848static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300849 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300850{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300851 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300852
853 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300854 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300855
856 if (flags == 0)
857 return scnprintf(bf, size, "RDONLY");
858#define P_FLAG(n) \
859 if (flags & O_##n) { \
860 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
861 flags &= ~O_##n; \
862 }
863
864 P_FLAG(APPEND);
865 P_FLAG(ASYNC);
866 P_FLAG(CLOEXEC);
867 P_FLAG(CREAT);
868 P_FLAG(DIRECT);
869 P_FLAG(DIRECTORY);
870 P_FLAG(EXCL);
871 P_FLAG(LARGEFILE);
872 P_FLAG(NOATIME);
873 P_FLAG(NOCTTY);
874#ifdef O_NONBLOCK
875 P_FLAG(NONBLOCK);
876#elif O_NDELAY
877 P_FLAG(NDELAY);
878#endif
879#ifdef O_PATH
880 P_FLAG(PATH);
881#endif
882 P_FLAG(RDWR);
883#ifdef O_DSYNC
884 if ((flags & O_SYNC) == O_SYNC)
885 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
886 else {
887 P_FLAG(DSYNC);
888 }
889#else
890 P_FLAG(SYNC);
891#endif
892 P_FLAG(TRUNC);
893 P_FLAG(WRONLY);
894#undef P_FLAG
895
896 if (flags)
897 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
898
899 return printed;
900}
901
902#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
903
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300904static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size,
905 struct syscall_arg *arg)
906{
907 int printed = 0, flags = arg->val;
908
909 if (flags == 0)
910 return 0;
911
912#define P_FLAG(n) \
913 if (flags & PERF_FLAG_##n) { \
914 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
915 flags &= ~PERF_FLAG_##n; \
916 }
917
918 P_FLAG(FD_NO_GROUP);
919 P_FLAG(FD_OUTPUT);
920 P_FLAG(PID_CGROUP);
921 P_FLAG(FD_CLOEXEC);
922#undef P_FLAG
923
924 if (flags)
925 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
926
927 return printed;
928}
929
930#define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags
931
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300932static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
933 struct syscall_arg *arg)
934{
935 int printed = 0, flags = arg->val;
936
937 if (flags == 0)
938 return scnprintf(bf, size, "NONE");
939#define P_FLAG(n) \
940 if (flags & EFD_##n) { \
941 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
942 flags &= ~EFD_##n; \
943 }
944
945 P_FLAG(SEMAPHORE);
946 P_FLAG(CLOEXEC);
947 P_FLAG(NONBLOCK);
948#undef P_FLAG
949
950 if (flags)
951 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
952
953 return printed;
954}
955
956#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
957
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300958static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
959 struct syscall_arg *arg)
960{
961 int printed = 0, flags = arg->val;
962
963#define P_FLAG(n) \
964 if (flags & O_##n) { \
965 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
966 flags &= ~O_##n; \
967 }
968
969 P_FLAG(CLOEXEC);
970 P_FLAG(NONBLOCK);
971#undef P_FLAG
972
973 if (flags)
974 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
975
976 return printed;
977}
978
979#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
980
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300981static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
982{
983 int sig = arg->val;
984
985 switch (sig) {
986#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
987 P_SIGNUM(HUP);
988 P_SIGNUM(INT);
989 P_SIGNUM(QUIT);
990 P_SIGNUM(ILL);
991 P_SIGNUM(TRAP);
992 P_SIGNUM(ABRT);
993 P_SIGNUM(BUS);
994 P_SIGNUM(FPE);
995 P_SIGNUM(KILL);
996 P_SIGNUM(USR1);
997 P_SIGNUM(SEGV);
998 P_SIGNUM(USR2);
999 P_SIGNUM(PIPE);
1000 P_SIGNUM(ALRM);
1001 P_SIGNUM(TERM);
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001002 P_SIGNUM(CHLD);
1003 P_SIGNUM(CONT);
1004 P_SIGNUM(STOP);
1005 P_SIGNUM(TSTP);
1006 P_SIGNUM(TTIN);
1007 P_SIGNUM(TTOU);
1008 P_SIGNUM(URG);
1009 P_SIGNUM(XCPU);
1010 P_SIGNUM(XFSZ);
1011 P_SIGNUM(VTALRM);
1012 P_SIGNUM(PROF);
1013 P_SIGNUM(WINCH);
1014 P_SIGNUM(IO);
1015 P_SIGNUM(PWR);
1016 P_SIGNUM(SYS);
Ben Hutchings02c5bb42014-02-06 01:00:41 +00001017#ifdef SIGEMT
1018 P_SIGNUM(EMT);
1019#endif
1020#ifdef SIGSTKFLT
1021 P_SIGNUM(STKFLT);
1022#endif
1023#ifdef SIGSWI
1024 P_SIGNUM(SWI);
1025#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001026 default: break;
1027 }
1028
1029 return scnprintf(bf, size, "%#x", sig);
1030}
1031
1032#define SCA_SIGNUM syscall_arg__scnprintf_signum
1033
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001034#if defined(__i386__) || defined(__x86_64__)
1035/*
1036 * FIXME: Make this available to all arches.
1037 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001038#define TCGETS 0x5401
1039
1040static const char *tioctls[] = {
1041 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
1042 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
1043 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
1044 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
1045 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
1046 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
1047 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
1048 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
1049 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
1050 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
1051 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
1052 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
1053 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
1054 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
1055 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
1056};
1057
1058static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001059#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001060
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001061static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg)
1062{
1063 int op = arg->val;
1064 size_t printed = 0;
1065
1066 switch (op) {
1067#define P_SECCOMP_SET_MODE_OP(n) case SECCOMP_SET_MODE_##n: printed = scnprintf(bf, size, #n); break
1068 P_SECCOMP_SET_MODE_OP(STRICT);
1069 P_SECCOMP_SET_MODE_OP(FILTER);
1070#undef P_SECCOMP_SET_MODE_OP
1071 default: printed = scnprintf(bf, size, "%#x", op); break;
1072 }
1073
1074 return printed;
1075}
1076
1077#define SCA_SECCOMP_OP syscall_arg__scnprintf_seccomp_op
1078
1079static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size,
1080 struct syscall_arg *arg)
1081{
1082 int printed = 0, flags = arg->val;
1083
1084#define P_FLAG(n) \
1085 if (flags & SECCOMP_FILTER_FLAG_##n) { \
1086 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
1087 flags &= ~SECCOMP_FILTER_FLAG_##n; \
1088 }
1089
1090 P_FLAG(TSYNC);
1091#undef P_FLAG
1092
1093 if (flags)
1094 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
1095
1096 return printed;
1097}
1098
1099#define SCA_SECCOMP_FLAGS syscall_arg__scnprintf_seccomp_flags
1100
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -03001101static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
1102 struct syscall_arg *arg)
1103{
1104 int printed = 0, flags = arg->val;
1105
1106#define P_FLAG(n) \
1107 if (flags & GRND_##n) { \
1108 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
1109 flags &= ~GRND_##n; \
1110 }
1111
1112 P_FLAG(RANDOM);
1113 P_FLAG(NONBLOCK);
1114#undef P_FLAG
1115
1116 if (flags)
1117 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
1118
1119 return printed;
1120}
1121
1122#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
1123
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001124#define STRARRAY(arg, name, array) \
1125 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
1126 .arg_parm = { [arg] = &strarray__##array, }
1127
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001128#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001129#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001130#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001131#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001132
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001133static struct syscall_fmt {
1134 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001135 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001136 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001137 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001138 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001139 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001140 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001141 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001142} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -03001143 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001144 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1145 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001146 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -03001147 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001148 { .name = "brk", .hexret = true,
1149 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001150 { .name = "chdir", .errmsg = true,
1151 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1152 { .name = "chmod", .errmsg = true,
1153 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1154 { .name = "chroot", .errmsg = true,
1155 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -06001156 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001157 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001158 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001159 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -03001160 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001161 { .name = "creat", .errmsg = true,
1162 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001163 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001164 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001165 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001166 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001167 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001168 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001169 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -03001170 { .name = "eventfd2", .errmsg = true,
1171 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001172 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001173 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1174 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001175 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001176 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001177 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001178 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001179 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001180 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001181 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001182 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001183 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001184 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1185 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001186 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001187 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001188 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001189 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1190 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001191 { .name = "fcntl", .errmsg = true,
1192 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1193 [1] = SCA_STRARRAY, /* cmd */ },
1194 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1195 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001196 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -03001197 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001198 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1199 [1] = SCA_FLOCK, /* cmd */ }, },
1200 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001201 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001202 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001203 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001204 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001205 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1206 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001207 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001208 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001209 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001210 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001211 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001212 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -03001213 { .name = "futex", .errmsg = true,
1214 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001215 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001216 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1217 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001218 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001219 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001220 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001221 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001222 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001223 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001224 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001225 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -03001226 { .name = "getrandom", .errmsg = true,
1227 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001228 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001229 { .name = "getxattr", .errmsg = true,
1230 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1231 { .name = "inotify_add_watch", .errmsg = true,
1232 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001233 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001234 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001235#if defined(__i386__) || defined(__x86_64__)
1236/*
1237 * FIXME: Make this available to all arches.
1238 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001239 [1] = SCA_STRHEXARRAY, /* cmd */
1240 [2] = SCA_HEX, /* arg */ },
1241 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001242#else
1243 [2] = SCA_HEX, /* arg */ }, },
1244#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -03001245 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001246 { .name = "kill", .errmsg = true,
1247 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001248 { .name = "lchown", .errmsg = true,
1249 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1250 { .name = "lgetxattr", .errmsg = true,
1251 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001252 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001253 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001254 { .name = "listxattr", .errmsg = true,
1255 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001256 { .name = "llistxattr", .errmsg = true,
1257 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1258 { .name = "lremovexattr", .errmsg = true,
1259 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001260 { .name = "lseek", .errmsg = true,
1261 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1262 [2] = SCA_STRARRAY, /* whence */ },
1263 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001264 { .name = "lsetxattr", .errmsg = true,
1265 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001266 { .name = "lstat", .errmsg = true, .alias = "newlstat",
1267 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001268 { .name = "lsxattr", .errmsg = true,
1269 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001270 { .name = "madvise", .errmsg = true,
1271 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1272 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001273 { .name = "mkdir", .errmsg = true,
1274 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001275 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001276 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1277 [1] = SCA_FILENAME, /* pathname */ }, },
1278 { .name = "mknod", .errmsg = true,
1279 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001280 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001281 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1282 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001283 { .name = "mlock", .errmsg = true,
1284 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1285 { .name = "mlockall", .errmsg = true,
1286 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001287 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001288 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001289 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001290 [3] = SCA_MMAP_FLAGS, /* flags */
1291 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001292 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001293 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1294 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001295 { .name = "mq_unlink", .errmsg = true,
1296 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001297 { .name = "mremap", .hexret = true,
1298 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001299 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001300 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001301 { .name = "munlock", .errmsg = true,
1302 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001303 { .name = "munmap", .errmsg = true,
1304 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001305 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001306 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001307 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001308 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1309 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001310 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001311 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1312 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001313 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001314 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1315 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001316 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001317 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001318 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001319 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001320 { .name = "perf_event_open", .errmsg = true,
1321 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1322 [2] = SCA_INT, /* cpu */
1323 [3] = SCA_FD, /* group_fd */
1324 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001325 { .name = "pipe2", .errmsg = true,
1326 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001327 { .name = "poll", .errmsg = true, .timeout = true, },
1328 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001329 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001330 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001331 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001332 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001333 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001334 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001335 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001336 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001337 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001338 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001339 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001340 { .name = "readlink", .errmsg = true,
1341 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001342 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001343 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1344 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001345 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001346 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001347 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001348 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1349 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001350 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001351 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1352 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001353 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001354 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1355 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001356 { .name = "removexattr", .errmsg = true,
1357 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001358 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001359 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001360 { .name = "rmdir", .errmsg = true,
1361 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001362 { .name = "rt_sigaction", .errmsg = true,
1363 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001364 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001365 { .name = "rt_sigqueueinfo", .errmsg = true,
1366 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1367 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1368 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001369 { .name = "sched_setscheduler", .errmsg = true,
1370 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001371 { .name = "seccomp", .errmsg = true,
1372 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
1373 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001374 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001375 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001376 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1377 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001378 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001379 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1380 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001381 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001382 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1383 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001384 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001385 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001386 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001387 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001388 { .name = "setxattr", .errmsg = true,
1389 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001390 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001391 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001392 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001393 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1394 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001395 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001396 { .name = "socketpair", .errmsg = true,
1397 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1398 [1] = SCA_SK_TYPE, /* type */ },
1399 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001400 { .name = "stat", .errmsg = true, .alias = "newstat",
1401 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001402 { .name = "statfs", .errmsg = true,
1403 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1404 { .name = "swapoff", .errmsg = true,
1405 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1406 { .name = "swapon", .errmsg = true,
1407 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001408 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001409 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001410 { .name = "tgkill", .errmsg = true,
1411 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1412 { .name = "tkill", .errmsg = true,
1413 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001414 { .name = "truncate", .errmsg = true,
1415 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001416 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001417 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001418 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1419 [1] = SCA_FILENAME, /* pathname */ }, },
1420 { .name = "utime", .errmsg = true,
1421 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001422 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001423 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1424 [1] = SCA_FILENAME, /* filename */ }, },
1425 { .name = "utimes", .errmsg = true,
1426 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001427 { .name = "vmsplice", .errmsg = true,
1428 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001429 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001430 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001431 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001432 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001433 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001434 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001435 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001436 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001437};
1438
1439static int syscall_fmt__cmp(const void *name, const void *fmtp)
1440{
1441 const struct syscall_fmt *fmt = fmtp;
1442 return strcmp(name, fmt->name);
1443}
1444
1445static struct syscall_fmt *syscall_fmt__find(const char *name)
1446{
1447 const int nmemb = ARRAY_SIZE(syscall_fmts);
1448 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1449}
1450
1451struct syscall {
1452 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001453 int nr_args;
1454 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001455 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001456 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001457 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001458 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001459 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001460};
1461
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001462static size_t fprintf_duration(unsigned long t, FILE *fp)
1463{
1464 double duration = (double)t / NSEC_PER_MSEC;
1465 size_t printed = fprintf(fp, "(");
1466
1467 if (duration >= 1.0)
1468 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1469 else if (duration >= 0.01)
1470 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1471 else
1472 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001473 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001474}
1475
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001476/**
1477 * filename.ptr: The filename char pointer that will be vfs_getname'd
1478 * filename.entry_str_pos: Where to insert the string translated from
1479 * filename.ptr by the vfs_getname tracepoint/kprobe.
1480 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001481struct thread_trace {
1482 u64 entry_time;
1483 u64 exit_time;
1484 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001485 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001486 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001487 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001488 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001489 struct {
1490 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001491 short int entry_str_pos;
1492 bool pending_open;
1493 unsigned int namelen;
1494 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001495 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001496 struct {
1497 int max;
1498 char **table;
1499 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001500
1501 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001502};
1503
1504static struct thread_trace *thread_trace__new(void)
1505{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001506 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1507
1508 if (ttrace)
1509 ttrace->paths.max = -1;
1510
David Ahernbf2575c2013-10-08 21:26:53 -06001511 ttrace->syscall_stats = intlist__new(NULL);
1512
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001513 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001514}
1515
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001516static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001517{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001518 struct thread_trace *ttrace;
1519
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001520 if (thread == NULL)
1521 goto fail;
1522
Namhyung Kim89dceb22014-10-06 09:46:03 +09001523 if (thread__priv(thread) == NULL)
1524 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001525
Namhyung Kim89dceb22014-10-06 09:46:03 +09001526 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001527 goto fail;
1528
Namhyung Kim89dceb22014-10-06 09:46:03 +09001529 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001530 ++ttrace->nr_events;
1531
1532 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001533fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001534 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001535 "WARNING: not enough memory, dropping samples!\n");
1536 return NULL;
1537}
1538
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001539#define TRACE_PFMAJ (1 << 0)
1540#define TRACE_PFMIN (1 << 1)
1541
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001542static const size_t trace__entry_str_size = 2048;
1543
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001544static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001545{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001546 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001547
1548 if (fd > ttrace->paths.max) {
1549 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1550
1551 if (npath == NULL)
1552 return -1;
1553
1554 if (ttrace->paths.max != -1) {
1555 memset(npath + ttrace->paths.max + 1, 0,
1556 (fd - ttrace->paths.max) * sizeof(char *));
1557 } else {
1558 memset(npath, 0, (fd + 1) * sizeof(char *));
1559 }
1560
1561 ttrace->paths.table = npath;
1562 ttrace->paths.max = fd;
1563 }
1564
1565 ttrace->paths.table[fd] = strdup(pathname);
1566
1567 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1568}
1569
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001570static int thread__read_fd_path(struct thread *thread, int fd)
1571{
1572 char linkname[PATH_MAX], pathname[PATH_MAX];
1573 struct stat st;
1574 int ret;
1575
1576 if (thread->pid_ == thread->tid) {
1577 scnprintf(linkname, sizeof(linkname),
1578 "/proc/%d/fd/%d", thread->pid_, fd);
1579 } else {
1580 scnprintf(linkname, sizeof(linkname),
1581 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1582 }
1583
1584 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1585 return -1;
1586
1587 ret = readlink(linkname, pathname, sizeof(pathname));
1588
1589 if (ret < 0 || ret > st.st_size)
1590 return -1;
1591
1592 pathname[ret] = '\0';
1593 return trace__set_fd_pathname(thread, fd, pathname);
1594}
1595
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001596static const char *thread__fd_path(struct thread *thread, int fd,
1597 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001598{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001599 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001600
1601 if (ttrace == NULL)
1602 return NULL;
1603
1604 if (fd < 0)
1605 return NULL;
1606
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001607 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001608 if (!trace->live)
1609 return NULL;
1610 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001611 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001612 return NULL;
1613 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001614
1615 return ttrace->paths.table[fd];
1616}
1617
1618static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1619 struct syscall_arg *arg)
1620{
1621 int fd = arg->val;
1622 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001623 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001624
1625 if (path)
1626 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1627
1628 return printed;
1629}
1630
1631static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1632 struct syscall_arg *arg)
1633{
1634 int fd = arg->val;
1635 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001636 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001637
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001638 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1639 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001640
1641 return printed;
1642}
1643
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001644static void thread__set_filename_pos(struct thread *thread, const char *bf,
1645 unsigned long ptr)
1646{
1647 struct thread_trace *ttrace = thread__priv(thread);
1648
1649 ttrace->filename.ptr = ptr;
1650 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1651}
1652
1653static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1654 struct syscall_arg *arg)
1655{
1656 unsigned long ptr = arg->val;
1657
1658 if (!arg->trace->vfs_getname)
1659 return scnprintf(bf, size, "%#x", ptr);
1660
1661 thread__set_filename_pos(arg->thread, bf, ptr);
1662 return 0;
1663}
1664
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001665static bool trace__filter_duration(struct trace *trace, double t)
1666{
1667 return t < (trace->duration_filter * NSEC_PER_MSEC);
1668}
1669
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001670static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1671{
1672 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1673
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001674 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001675}
1676
Namhyung Kimf15eb532012-10-05 14:02:16 +09001677static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001678static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001679
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001680static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001681{
1682 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001683 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001684}
1685
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001686static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001687 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001688{
1689 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001690 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001691
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001692 if (trace->multiple_threads) {
1693 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001694 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001695 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001696 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001697
1698 return printed;
1699}
1700
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001701static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001702 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001703{
1704 int ret = 0;
1705
1706 switch (event->header.type) {
1707 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001708 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001709 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001710 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001711 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001712 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001713 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001714 break;
1715 }
1716
1717 return ret;
1718}
1719
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001720static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001721 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001722 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001723 struct machine *machine)
1724{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001725 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001726 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001727}
1728
1729static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1730{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001731 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001732
1733 if (err)
1734 return err;
1735
David Ahern8fb598e2013-09-28 13:13:00 -06001736 trace->host = machine__new_host();
1737 if (trace->host == NULL)
1738 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001739
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001740 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001741 return -errno;
1742
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001743 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001744 evlist->threads, trace__tool_process, false,
1745 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001746 if (err)
1747 symbol__exit();
1748
1749 return err;
1750}
1751
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001752static int syscall__set_arg_fmts(struct syscall *sc)
1753{
1754 struct format_field *field;
1755 int idx = 0;
1756
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001757 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001758 if (sc->arg_scnprintf == NULL)
1759 return -1;
1760
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001761 if (sc->fmt)
1762 sc->arg_parm = sc->fmt->arg_parm;
1763
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001764 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001765 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1766 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1767 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001768 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001769 else if (strcmp(field->type, "pid_t") == 0)
1770 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001771 else if (strcmp(field->type, "umode_t") == 0)
1772 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001773 ++idx;
1774 }
1775
1776 return 0;
1777}
1778
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001779static int trace__read_syscall_info(struct trace *trace, int id)
1780{
1781 char tp_name[128];
1782 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001783 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001784
1785 if (name == NULL)
1786 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001787
1788 if (id > trace->syscalls.max) {
1789 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1790
1791 if (nsyscalls == NULL)
1792 return -1;
1793
1794 if (trace->syscalls.max != -1) {
1795 memset(nsyscalls + trace->syscalls.max + 1, 0,
1796 (id - trace->syscalls.max) * sizeof(*sc));
1797 } else {
1798 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1799 }
1800
1801 trace->syscalls.table = nsyscalls;
1802 trace->syscalls.max = id;
1803 }
1804
1805 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001806 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001807
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001808 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001809
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001810 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001811 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001812
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001813 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001814 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001815 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001816 }
1817
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001818 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001819 return -1;
1820
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001821 sc->args = sc->tp_format->format.fields;
1822 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001823 /*
1824 * We need to check and discard the first variable '__syscall_nr'
1825 * or 'nr' that mean the syscall number. It is needless here.
1826 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1827 */
1828 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001829 sc->args = sc->args->next;
1830 --sc->nr_args;
1831 }
1832
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001833 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1834
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001835 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001836}
1837
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001838static int trace__validate_ev_qualifier(struct trace *trace)
1839{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001840 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001841 struct str_node *pos;
1842
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001843 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1844 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1845 sizeof(trace->ev_qualifier_ids.entries[0]));
1846
1847 if (trace->ev_qualifier_ids.entries == NULL) {
1848 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1849 trace->output);
1850 err = -EINVAL;
1851 goto out;
1852 }
1853
1854 i = 0;
1855
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001856 strlist__for_each(pos, trace->ev_qualifier) {
1857 const char *sc = pos->s;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001858 int id = audit_name_to_syscall(sc, trace->audit.machine);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001859
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001860 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001861 if (err == 0) {
1862 fputs("Error:\tInvalid syscall ", trace->output);
1863 err = -EINVAL;
1864 } else {
1865 fputs(", ", trace->output);
1866 }
1867
1868 fputs(sc, trace->output);
1869 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001870
1871 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001872 }
1873
1874 if (err < 0) {
1875 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1876 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001877 zfree(&trace->ev_qualifier_ids.entries);
1878 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001879 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001880out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001881 return err;
1882}
1883
David Ahern55d43bc2015-02-19 15:00:22 -05001884/*
1885 * args is to be interpreted as a series of longs but we need to handle
1886 * 8-byte unaligned accesses. args points to raw_data within the event
1887 * and raw_data is guaranteed to be 8-byte unaligned because it is
1888 * preceded by raw_size which is a u32. So we need to copy args to a temp
1889 * variable to read it. Most notably this avoids extended load instructions
1890 * on unaligned addresses
1891 */
1892
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001893static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001894 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001895 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001896{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001897 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001898 unsigned char *p;
1899 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001900
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001901 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001902 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001903 u8 bit = 1;
1904 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001905 .idx = 0,
1906 .mask = 0,
1907 .trace = trace,
1908 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001909 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001910
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001911 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001912 field = field->next, ++arg.idx, bit <<= 1) {
1913 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001914 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001915
1916 /* special care for unaligned accesses */
1917 p = args + sizeof(unsigned long) * arg.idx;
1918 memcpy(&val, p, sizeof(val));
1919
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001920 /*
1921 * Suppress this argument if its value is zero and
1922 * and we don't have a string associated in an
1923 * strarray for it.
1924 */
David Ahern55d43bc2015-02-19 15:00:22 -05001925 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001926 !(sc->arg_scnprintf &&
1927 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1928 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001929 continue;
1930
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001931 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001932 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001933 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001934 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001935 if (sc->arg_parm)
1936 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001937 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1938 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001939 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001940 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001941 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001942 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001943 }
1944 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001945 int i = 0;
1946
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001947 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001948 /* special care for unaligned accesses */
1949 p = args + sizeof(unsigned long) * i;
1950 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001951 printed += scnprintf(bf + printed, size - printed,
1952 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001953 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001954 ++i;
1955 }
1956 }
1957
1958 return printed;
1959}
1960
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001961typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001962 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001963 struct perf_sample *sample);
1964
1965static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001966 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001967{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001968
1969 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001970
1971 /*
1972 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1973 * before that, leaving at a higher verbosity level till that is
1974 * explained. Reproduced with plain ftrace with:
1975 *
1976 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1977 * grep "NR -1 " /t/trace_pipe
1978 *
1979 * After generating some load on the machine.
1980 */
1981 if (verbose > 1) {
1982 static u64 n;
1983 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1984 id, perf_evsel__name(evsel), ++n);
1985 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001986 return NULL;
1987 }
1988
1989 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1990 trace__read_syscall_info(trace, id))
1991 goto out_cant_read;
1992
1993 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1994 goto out_cant_read;
1995
1996 return &trace->syscalls.table[id];
1997
1998out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001999 if (verbose) {
2000 fprintf(trace->output, "Problems reading syscall %d", id);
2001 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
2002 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
2003 fputs(" information\n", trace->output);
2004 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002005 return NULL;
2006}
2007
David Ahernbf2575c2013-10-08 21:26:53 -06002008static void thread__update_stats(struct thread_trace *ttrace,
2009 int id, struct perf_sample *sample)
2010{
2011 struct int_node *inode;
2012 struct stats *stats;
2013 u64 duration = 0;
2014
2015 inode = intlist__findnew(ttrace->syscall_stats, id);
2016 if (inode == NULL)
2017 return;
2018
2019 stats = inode->priv;
2020 if (stats == NULL) {
2021 stats = malloc(sizeof(struct stats));
2022 if (stats == NULL)
2023 return;
2024 init_stats(stats);
2025 inode->priv = stats;
2026 }
2027
2028 if (ttrace->entry_time && sample->time > ttrace->entry_time)
2029 duration = sample->time - ttrace->entry_time;
2030
2031 update_stats(stats, duration);
2032}
2033
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03002034static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
2035{
2036 struct thread_trace *ttrace;
2037 u64 duration;
2038 size_t printed;
2039
2040 if (trace->current == NULL)
2041 return 0;
2042
2043 ttrace = thread__priv(trace->current);
2044
2045 if (!ttrace->entry_pending)
2046 return 0;
2047
2048 duration = sample->time - ttrace->entry_time;
2049
2050 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
2051 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
2052 ttrace->entry_pending = false;
2053
2054 return printed;
2055}
2056
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002057static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002058 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002059 struct perf_sample *sample)
2060{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002061 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002062 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002063 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002064 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002065 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002066 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002067 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002068
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002069 if (sc == NULL)
2070 return -1;
2071
David Ahern8fb598e2013-09-28 13:13:00 -06002072 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002073 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002074 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002075 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002076
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002077 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002078
2079 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002080 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002081 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002082 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002083 }
2084
David Ahern13f22a22015-03-19 12:23:03 -06002085 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03002086 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03002087
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002088 ttrace->entry_time = sample->time;
2089 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002090 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002091
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002092 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002093 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002094
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03002095 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07002096 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002097 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
2098 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002099 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002100 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002101 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002102 /* See trace__vfs_getname & trace__sys_exit */
2103 ttrace->filename.pending_open = false;
2104 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002105
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002106 if (trace->current != thread) {
2107 thread__put(trace->current);
2108 trace->current = thread__get(thread);
2109 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002110 err = 0;
2111out_put:
2112 thread__put(thread);
2113 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002114}
2115
2116static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002117 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002118 struct perf_sample *sample)
2119{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002120 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002121 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002122 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002123 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002124 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002125 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002126
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002127 if (sc == NULL)
2128 return -1;
2129
David Ahern8fb598e2013-09-28 13:13:00 -06002130 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002131 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002132 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002133 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002134
David Ahernbf2575c2013-10-08 21:26:53 -06002135 if (trace->summary)
2136 thread__update_stats(ttrace, id, sample);
2137
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002138 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002139
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002140 if (id == trace->audit.open_id && ret >= 0 && ttrace->filename.pending_open) {
2141 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
2142 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002143 ++trace->stats.vfs_getname;
2144 }
2145
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002146 ttrace->exit_time = sample->time;
2147
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002148 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002149 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002150 if (trace__filter_duration(trace, duration))
2151 goto out;
2152 } else if (trace->duration_filter)
2153 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002154
David Ahernfd2eaba2013-11-12 09:31:15 -07002155 if (trace->summary_only)
2156 goto out;
2157
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002158 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002159
2160 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002161 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002162 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002163 fprintf(trace->output, " ... [");
2164 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
2165 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002166 }
2167
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002168 if (sc->fmt == NULL) {
2169signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002170 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03002171 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00002172 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002173 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
2174 *e = audit_errno_to_name(-ret);
2175
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002176 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002177 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002178 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03002179 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002180 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03002181 else if (sc->fmt->errpid) {
2182 struct thread *child = machine__find_thread(trace->host, ret, ret);
2183
2184 if (child != NULL) {
2185 fprintf(trace->output, ") = %ld", ret);
2186 if (child->comm_set)
2187 fprintf(trace->output, " (%s)", thread__comm_str(child));
2188 thread__put(child);
2189 }
2190 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002191 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002192
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002193 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002194out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002195 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002196 err = 0;
2197out_put:
2198 thread__put(thread);
2199 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002200}
2201
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002202static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002203 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002204 struct perf_sample *sample)
2205{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002206 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2207 struct thread_trace *ttrace;
2208 size_t filename_len, entry_str_len, to_move;
2209 ssize_t remaining_space;
2210 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002211 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002212
2213 if (!thread)
2214 goto out;
2215
2216 ttrace = thread__priv(thread);
2217 if (!ttrace)
2218 goto out;
2219
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002220 filename_len = strlen(filename);
2221
2222 if (ttrace->filename.namelen < filename_len) {
2223 char *f = realloc(ttrace->filename.name, filename_len + 1);
2224
2225 if (f == NULL)
2226 goto out;
2227
2228 ttrace->filename.namelen = filename_len;
2229 ttrace->filename.name = f;
2230 }
2231
2232 strcpy(ttrace->filename.name, filename);
2233 ttrace->filename.pending_open = true;
2234
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002235 if (!ttrace->filename.ptr)
2236 goto out;
2237
2238 entry_str_len = strlen(ttrace->entry_str);
2239 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2240 if (remaining_space <= 0)
2241 goto out;
2242
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002243 if (filename_len > (size_t)remaining_space) {
2244 filename += filename_len - remaining_space;
2245 filename_len = remaining_space;
2246 }
2247
2248 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2249 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2250 memmove(pos + filename_len, pos, to_move);
2251 memcpy(pos, filename, filename_len);
2252
2253 ttrace->filename.ptr = 0;
2254 ttrace->filename.entry_str_pos = 0;
2255out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002256 return 0;
2257}
2258
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002259static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002260 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002261 struct perf_sample *sample)
2262{
2263 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2264 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06002265 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03002266 sample->pid,
2267 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002268 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002269
2270 if (ttrace == NULL)
2271 goto out_dump;
2272
2273 ttrace->runtime_ms += runtime_ms;
2274 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002275 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002276 return 0;
2277
2278out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002279 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002280 evsel->name,
2281 perf_evsel__strval(evsel, sample, "comm"),
2282 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2283 runtime,
2284 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002285 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002286 return 0;
2287}
2288
Wang Nan1d6c9402016-02-26 09:31:55 +00002289static void bpf_output__printer(enum binary_printer_ops op,
2290 unsigned int val, void *extra)
2291{
2292 FILE *output = extra;
2293 unsigned char ch = (unsigned char)val;
2294
2295 switch (op) {
2296 case BINARY_PRINT_CHAR_DATA:
2297 fprintf(output, "%c", isprint(ch) ? ch : '.');
2298 break;
2299 case BINARY_PRINT_DATA_BEGIN:
2300 case BINARY_PRINT_LINE_BEGIN:
2301 case BINARY_PRINT_ADDR:
2302 case BINARY_PRINT_NUM_DATA:
2303 case BINARY_PRINT_NUM_PAD:
2304 case BINARY_PRINT_SEP:
2305 case BINARY_PRINT_CHAR_PAD:
2306 case BINARY_PRINT_LINE_END:
2307 case BINARY_PRINT_DATA_END:
2308 default:
2309 break;
2310 }
2311}
2312
2313static void bpf_output__fprintf(struct trace *trace,
2314 struct perf_sample *sample)
2315{
2316 print_binary(sample->raw_data, sample->raw_size, 8,
2317 bpf_output__printer, trace->output);
2318}
2319
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002320static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2321 union perf_event *event __maybe_unused,
2322 struct perf_sample *sample)
2323{
2324 trace__printf_interrupted_entry(trace, sample);
2325 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002326
2327 if (trace->trace_syscalls)
2328 fprintf(trace->output, "( ): ");
2329
2330 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002331
Wang Nan1d6c9402016-02-26 09:31:55 +00002332 if (perf_evsel__is_bpf_output(evsel)) {
2333 bpf_output__fprintf(trace, sample);
2334 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002335 event_format__fprintf(evsel->tp_format, sample->cpu,
2336 sample->raw_data, sample->raw_size,
2337 trace->output);
2338 }
2339
2340 fprintf(trace->output, ")\n");
2341 return 0;
2342}
2343
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002344static void print_location(FILE *f, struct perf_sample *sample,
2345 struct addr_location *al,
2346 bool print_dso, bool print_sym)
2347{
2348
2349 if ((verbose || print_dso) && al->map)
2350 fprintf(f, "%s@", al->map->dso->long_name);
2351
2352 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002353 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002354 al->addr - al->sym->start);
2355 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002356 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002357 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002358 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002359}
2360
2361static int trace__pgfault(struct trace *trace,
2362 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002363 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002364 struct perf_sample *sample)
2365{
2366 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002367 struct addr_location al;
2368 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002369 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002370 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002371
2372 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002373 ttrace = thread__trace(thread, trace->output);
2374 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002375 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002376
2377 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2378 ttrace->pfmaj++;
2379 else
2380 ttrace->pfmin++;
2381
2382 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002383 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002384
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002385 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002386 sample->ip, &al);
2387
2388 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2389
2390 fprintf(trace->output, "%sfault [",
2391 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2392 "maj" : "min");
2393
2394 print_location(trace->output, sample, &al, false, true);
2395
2396 fprintf(trace->output, "] => ");
2397
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002398 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002399 sample->addr, &al);
2400
2401 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002402 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002403 MAP__FUNCTION, sample->addr, &al);
2404
2405 if (al.map)
2406 map_type = 'x';
2407 else
2408 map_type = '?';
2409 }
2410
2411 print_location(trace->output, sample, &al, true, false);
2412
2413 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002414out:
2415 err = 0;
2416out_put:
2417 thread__put(thread);
2418 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002419}
2420
David Ahernbdc89662013-08-28 22:29:53 -06002421static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2422{
2423 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2424 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2425 return false;
2426
2427 if (trace->pid_list || trace->tid_list)
2428 return true;
2429
2430 return false;
2431}
2432
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002433static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002434 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002435 struct perf_sample *sample)
2436{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002437 /*
2438 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2439 * and don't use sample->time unconditionally, we may end up having
2440 * some other event in the future without PERF_SAMPLE_TIME for good
2441 * reason, i.e. we may not be interested in its timestamps, just in
2442 * it taking place, picking some piece of information when it
2443 * appears in our event stream (vfs_getname comes to mind).
2444 */
2445 if (trace->base_time == 0 && !trace->full_time &&
2446 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002447 trace->base_time = sample->time;
2448}
2449
David Ahern6810fc92013-08-28 22:29:52 -06002450static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002451 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002452 struct perf_sample *sample,
2453 struct perf_evsel *evsel,
2454 struct machine *machine __maybe_unused)
2455{
2456 struct trace *trace = container_of(tool, struct trace, tool);
2457 int err = 0;
2458
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002459 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002460
David Ahernbdc89662013-08-28 22:29:53 -06002461 if (skip_sample(trace, sample))
2462 return 0;
2463
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002464 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002465
David Ahern31605652013-12-04 19:41:41 -07002466 if (handler) {
2467 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002468 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002469 }
David Ahern6810fc92013-08-28 22:29:52 -06002470
2471 return err;
2472}
2473
David Ahernbdc89662013-08-28 22:29:53 -06002474static int parse_target_str(struct trace *trace)
2475{
2476 if (trace->opts.target.pid) {
2477 trace->pid_list = intlist__new(trace->opts.target.pid);
2478 if (trace->pid_list == NULL) {
2479 pr_err("Error parsing process id string\n");
2480 return -EINVAL;
2481 }
2482 }
2483
2484 if (trace->opts.target.tid) {
2485 trace->tid_list = intlist__new(trace->opts.target.tid);
2486 if (trace->tid_list == NULL) {
2487 pr_err("Error parsing thread id string\n");
2488 return -EINVAL;
2489 }
2490 }
2491
2492 return 0;
2493}
2494
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002495static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002496{
2497 unsigned int rec_argc, i, j;
2498 const char **rec_argv;
2499 const char * const record_args[] = {
2500 "record",
2501 "-R",
2502 "-m", "1024",
2503 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002504 };
2505
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002506 const char * const sc_args[] = { "-e", };
2507 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2508 const char * const majpf_args[] = { "-e", "major-faults" };
2509 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2510 const char * const minpf_args[] = { "-e", "minor-faults" };
2511 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2512
David Ahern9aca7f12013-12-04 19:41:39 -07002513 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002514 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2515 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002516 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2517
2518 if (rec_argv == NULL)
2519 return -ENOMEM;
2520
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002521 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002522 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002523 rec_argv[j++] = record_args[i];
2524
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002525 if (trace->trace_syscalls) {
2526 for (i = 0; i < sc_args_nr; i++)
2527 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002528
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002529 /* event string may be different for older kernels - e.g., RHEL6 */
2530 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2531 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2532 else if (is_valid_tracepoint("syscalls:sys_enter"))
2533 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2534 else {
2535 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2536 return -1;
2537 }
David Ahern9aca7f12013-12-04 19:41:39 -07002538 }
David Ahern9aca7f12013-12-04 19:41:39 -07002539
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002540 if (trace->trace_pgfaults & TRACE_PFMAJ)
2541 for (i = 0; i < majpf_args_nr; i++)
2542 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002543
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002544 if (trace->trace_pgfaults & TRACE_PFMIN)
2545 for (i = 0; i < minpf_args_nr; i++)
2546 rec_argv[j++] = minpf_args[i];
2547
2548 for (i = 0; i < (unsigned int)argc; i++)
2549 rec_argv[j++] = argv[i];
2550
2551 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002552}
2553
David Ahernbf2575c2013-10-08 21:26:53 -06002554static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2555
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002556static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002557{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002558 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002559
2560 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002561 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002562
2563 if (perf_evsel__field(evsel, "pathname") == NULL) {
2564 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002565 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002566 }
2567
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002568 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002569 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002570 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002571}
2572
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002573static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2574 u64 config)
2575{
2576 struct perf_evsel *evsel;
2577 struct perf_event_attr attr = {
2578 .type = PERF_TYPE_SOFTWARE,
2579 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002580 };
2581
2582 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002583 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002584
2585 event_attr_init(&attr);
2586
2587 evsel = perf_evsel__new(&attr);
2588 if (!evsel)
2589 return -ENOMEM;
2590
2591 evsel->handler = trace__pgfault;
2592 perf_evlist__add(evlist, evsel);
2593
2594 return 0;
2595}
2596
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002597static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2598{
2599 const u32 type = event->header.type;
2600 struct perf_evsel *evsel;
2601
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002602 if (type != PERF_RECORD_SAMPLE) {
2603 trace__process_event(trace, trace->host, event, sample);
2604 return;
2605 }
2606
2607 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2608 if (evsel == NULL) {
2609 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2610 return;
2611 }
2612
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002613 trace__set_base_time(trace, evsel, sample);
2614
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002615 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2616 sample->raw_data == NULL) {
2617 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2618 perf_evsel__name(evsel), sample->tid,
2619 sample->cpu, sample->raw_size);
2620 } else {
2621 tracepoint_handler handler = evsel->handler;
2622 handler(trace, evsel, event, sample);
2623 }
2624}
2625
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002626static int trace__add_syscall_newtp(struct trace *trace)
2627{
2628 int ret = -1;
2629 struct perf_evlist *evlist = trace->evlist;
2630 struct perf_evsel *sys_enter, *sys_exit;
2631
2632 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2633 if (sys_enter == NULL)
2634 goto out;
2635
2636 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2637 goto out_delete_sys_enter;
2638
2639 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2640 if (sys_exit == NULL)
2641 goto out_delete_sys_enter;
2642
2643 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2644 goto out_delete_sys_exit;
2645
2646 perf_evlist__add(evlist, sys_enter);
2647 perf_evlist__add(evlist, sys_exit);
2648
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002649 trace->syscalls.events.sys_enter = sys_enter;
2650 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002651
2652 ret = 0;
2653out:
2654 return ret;
2655
2656out_delete_sys_exit:
2657 perf_evsel__delete_priv(sys_exit);
2658out_delete_sys_enter:
2659 perf_evsel__delete_priv(sys_enter);
2660 goto out;
2661}
2662
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002663static int trace__set_ev_qualifier_filter(struct trace *trace)
2664{
2665 int err = -1;
2666 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2667 trace->ev_qualifier_ids.nr,
2668 trace->ev_qualifier_ids.entries);
2669
2670 if (filter == NULL)
2671 goto out_enomem;
2672
2673 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2674 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2675
2676 free(filter);
2677out:
2678 return err;
2679out_enomem:
2680 errno = ENOMEM;
2681 goto out;
2682}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002683
Namhyung Kimf15eb532012-10-05 14:02:16 +09002684static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002685{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002686 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002687 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002688 int err = -1, i;
2689 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002690 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002691 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002692
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002693 trace->live = true;
2694
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002695 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002696 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002697
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002698 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002699 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002700
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002701 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002702 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002703 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002704 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002705
2706 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2707 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002708 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002709
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002710 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002711 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2712 trace__sched_stat_runtime))
2713 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002714
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002715 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2716 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002717 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002718 goto out_delete_evlist;
2719 }
2720
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002721 err = trace__symbols_init(trace, evlist);
2722 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002723 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002724 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002725 }
2726
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002727 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002728
Namhyung Kimf15eb532012-10-05 14:02:16 +09002729 signal(SIGCHLD, sig_handler);
2730 signal(SIGINT, sig_handler);
2731
2732 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002733 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002734 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002735 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002736 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002737 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002738 }
2739 }
2740
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002741 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002742 if (err < 0)
2743 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002744
Wang Nanba504232016-02-26 09:31:54 +00002745 err = bpf__apply_obj_config();
2746 if (err) {
2747 char errbuf[BUFSIZ];
2748
2749 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2750 pr_err("ERROR: Apply config to BPF failed: %s\n",
2751 errbuf);
2752 goto out_error_open;
2753 }
2754
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002755 /*
2756 * Better not use !target__has_task() here because we need to cover the
2757 * case where no threads were specified in the command line, but a
2758 * workload was, and in that case we will fill in the thread_map when
2759 * we fork the workload in perf_evlist__prepare_workload.
2760 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002761 if (trace->filter_pids.nr > 0)
2762 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002763 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002764 err = perf_evlist__set_filter_pid(evlist, getpid());
2765
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002766 if (err < 0)
2767 goto out_error_mem;
2768
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002769 if (trace->ev_qualifier_ids.nr > 0) {
2770 err = trace__set_ev_qualifier_filter(trace);
2771 if (err < 0)
2772 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002773
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002774 pr_debug("event qualifier tracepoint filter: %s\n",
2775 trace->syscalls.events.sys_exit->filter);
2776 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002777
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002778 err = perf_evlist__apply_filters(evlist, &evsel);
2779 if (err < 0)
2780 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002781
Jiri Olsaf8850372013-11-28 17:57:22 +01002782 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002783 if (err < 0)
2784 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002785
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002786 if (!target__none(&trace->opts.target))
2787 perf_evlist__enable(evlist);
2788
Namhyung Kimf15eb532012-10-05 14:02:16 +09002789 if (forks)
2790 perf_evlist__start_workload(evlist);
2791
Jiri Olsae13798c2015-06-23 00:36:02 +02002792 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002793 evlist->threads->nr > 1 ||
2794 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002795again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002796 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002797
2798 for (i = 0; i < evlist->nr_mmaps; i++) {
2799 union perf_event *event;
2800
2801 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002802 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002803
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002804 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002805
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002806 err = perf_evlist__parse_sample(evlist, event, &sample);
2807 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002808 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002809 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002810 }
2811
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002812 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002813next_event:
2814 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002815
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002816 if (interrupted)
2817 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002818
2819 if (done && !draining) {
2820 perf_evlist__disable(evlist);
2821 draining = true;
2822 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002823 }
2824 }
2825
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002826 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002827 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002828
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002829 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2830 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2831 draining = true;
2832
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002833 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002834 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002835 } else {
2836 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002837 }
2838
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002839out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002840 thread__zput(trace->current);
2841
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002842 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002843
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002844 if (!err) {
2845 if (trace->summary)
2846 trace__fprintf_thread_summary(trace, trace->output);
2847
2848 if (trace->show_tool_stats) {
2849 fprintf(trace->output, "Stats:\n "
2850 " vfs_getname : %" PRIu64 "\n"
2851 " proc_getname: %" PRIu64 "\n",
2852 trace->stats.vfs_getname,
2853 trace->stats.proc_getname);
2854 }
2855 }
David Ahernbf2575c2013-10-08 21:26:53 -06002856
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002857out_delete_evlist:
2858 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002859 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002860 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002861 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002862{
2863 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002864
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002865out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002866 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002867 goto out_error;
2868
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002869out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002870 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002871 goto out_error;
2872
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002873out_error_mmap:
2874 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2875 goto out_error;
2876
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002877out_error_open:
2878 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2879
2880out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002881 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302882 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002883
2884out_error_apply_filters:
2885 fprintf(trace->output,
2886 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2887 evsel->filter, perf_evsel__name(evsel), errno,
2888 strerror_r(errno, errbuf, sizeof(errbuf)));
2889 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002890}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002891out_error_mem:
2892 fprintf(trace->output, "Not enough memory to run!\n");
2893 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002894
2895out_errno:
2896 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2897 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002898}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002899
David Ahern6810fc92013-08-28 22:29:52 -06002900static int trace__replay(struct trace *trace)
2901{
2902 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002903 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002904 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002905 struct perf_data_file file = {
2906 .path = input_name,
2907 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002908 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002909 };
David Ahern6810fc92013-08-28 22:29:52 -06002910 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002911 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002912 int err = -1;
2913
2914 trace->tool.sample = trace__process_sample;
2915 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002916 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002917 trace->tool.comm = perf_event__process_comm;
2918 trace->tool.exit = perf_event__process_exit;
2919 trace->tool.fork = perf_event__process_fork;
2920 trace->tool.attr = perf_event__process_attr;
2921 trace->tool.tracing_data = perf_event__process_tracing_data;
2922 trace->tool.build_id = perf_event__process_build_id;
2923
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002924 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002925 trace->tool.ordering_requires_timestamps = true;
2926
2927 /* add tid to output */
2928 trace->multiple_threads = true;
2929
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002930 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002931 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002932 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002933
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002934 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002935 goto out;
2936
David Ahern8fb598e2013-09-28 13:13:00 -06002937 trace->host = &session->machines.host;
2938
David Ahern6810fc92013-08-28 22:29:52 -06002939 err = perf_session__set_tracepoints_handlers(session, handlers);
2940 if (err)
2941 goto out;
2942
Namhyung Kim003824e2013-11-12 15:25:00 +09002943 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2944 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002945 /* older kernels have syscalls tp versus raw_syscalls */
2946 if (evsel == NULL)
2947 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2948 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002949
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002950 if (evsel &&
2951 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2952 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002953 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2954 goto out;
2955 }
2956
2957 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2958 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002959 if (evsel == NULL)
2960 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2961 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002962 if (evsel &&
2963 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2964 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002965 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002966 goto out;
2967 }
2968
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002969 evlist__for_each(session->evlist, evsel) {
2970 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2971 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2972 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2973 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2974 evsel->handler = trace__pgfault;
2975 }
2976
David Ahernbdc89662013-08-28 22:29:53 -06002977 err = parse_target_str(trace);
2978 if (err != 0)
2979 goto out;
2980
David Ahern6810fc92013-08-28 22:29:52 -06002981 setup_pager();
2982
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002983 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002984 if (err)
2985 pr_err("Failed to process events, error %d", err);
2986
David Ahernbf2575c2013-10-08 21:26:53 -06002987 else if (trace->summary)
2988 trace__fprintf_thread_summary(trace, trace->output);
2989
David Ahern6810fc92013-08-28 22:29:52 -06002990out:
2991 perf_session__delete(session);
2992
2993 return err;
2994}
2995
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002996static size_t trace__fprintf_threads_header(FILE *fp)
2997{
2998 size_t printed;
2999
Pekka Enberg99ff7152013-11-12 16:42:14 +02003000 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06003001
3002 return printed;
3003}
3004
3005static size_t thread__dump_stats(struct thread_trace *ttrace,
3006 struct trace *trace, FILE *fp)
3007{
3008 struct stats *stats;
3009 size_t printed = 0;
3010 struct syscall *sc;
3011 struct int_node *inode = intlist__first(ttrace->syscall_stats);
3012
3013 if (inode == NULL)
3014 return 0;
3015
3016 printed += fprintf(fp, "\n");
3017
Milian Wolff834fd462015-08-06 11:24:29 +02003018 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
3019 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
3020 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02003021
David Ahernbf2575c2013-10-08 21:26:53 -06003022 /* each int_node is a syscall */
3023 while (inode) {
3024 stats = inode->priv;
3025 if (stats) {
3026 double min = (double)(stats->min) / NSEC_PER_MSEC;
3027 double max = (double)(stats->max) / NSEC_PER_MSEC;
3028 double avg = avg_stats(stats);
3029 double pct;
3030 u64 n = (u64) stats->n;
3031
3032 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
3033 avg /= NSEC_PER_MSEC;
3034
3035 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02003036 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02003037 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
3038 n, avg * n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02003039 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06003040 }
3041
3042 inode = intlist__next(inode);
3043 }
3044
3045 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003046
3047 return printed;
3048}
3049
David Ahern896cbb52013-09-28 13:12:59 -06003050/* struct used to pass data to per-thread function */
3051struct summary_data {
3052 FILE *fp;
3053 struct trace *trace;
3054 size_t printed;
3055};
3056
3057static int trace__fprintf_one_thread(struct thread *thread, void *priv)
3058{
3059 struct summary_data *data = priv;
3060 FILE *fp = data->fp;
3061 size_t printed = data->printed;
3062 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09003063 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06003064 double ratio;
3065
3066 if (ttrace == NULL)
3067 return 0;
3068
3069 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
3070
Pekka Enberg15e65c62013-11-14 18:43:30 +02003071 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003072 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02003073 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04003074 if (ttrace->pfmaj)
3075 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
3076 if (ttrace->pfmin)
3077 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003078 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06003079 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06003080
3081 data->printed += printed;
3082
3083 return 0;
3084}
3085
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003086static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
3087{
David Ahern896cbb52013-09-28 13:12:59 -06003088 struct summary_data data = {
3089 .fp = fp,
3090 .trace = trace
3091 };
3092 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003093
David Ahern896cbb52013-09-28 13:12:59 -06003094 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003095
David Ahern896cbb52013-09-28 13:12:59 -06003096 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003097}
3098
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003099static int trace__set_duration(const struct option *opt, const char *str,
3100 int unset __maybe_unused)
3101{
3102 struct trace *trace = opt->value;
3103
3104 trace->duration_filter = atof(str);
3105 return 0;
3106}
3107
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08003108static int trace__set_filter_pids(const struct option *opt, const char *str,
3109 int unset __maybe_unused)
3110{
3111 int ret = -1;
3112 size_t i;
3113 struct trace *trace = opt->value;
3114 /*
3115 * FIXME: introduce a intarray class, plain parse csv and create a
3116 * { int nr, int entries[] } struct...
3117 */
3118 struct intlist *list = intlist__new(str);
3119
3120 if (list == NULL)
3121 return -1;
3122
3123 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
3124 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
3125
3126 if (trace->filter_pids.entries == NULL)
3127 goto out;
3128
3129 trace->filter_pids.entries[0] = getpid();
3130
3131 for (i = 1; i < trace->filter_pids.nr; ++i)
3132 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
3133
3134 intlist__delete(list);
3135 ret = 0;
3136out:
3137 return ret;
3138}
3139
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003140static int trace__open_output(struct trace *trace, const char *filename)
3141{
3142 struct stat st;
3143
3144 if (!stat(filename, &st) && st.st_size) {
3145 char oldname[PATH_MAX];
3146
3147 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
3148 unlink(oldname);
3149 rename(filename, oldname);
3150 }
3151
3152 trace->output = fopen(filename, "w");
3153
3154 return trace->output == NULL ? -errno : 0;
3155}
3156
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003157static int parse_pagefaults(const struct option *opt, const char *str,
3158 int unset __maybe_unused)
3159{
3160 int *trace_pgfaults = opt->value;
3161
3162 if (strcmp(str, "all") == 0)
3163 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
3164 else if (strcmp(str, "maj") == 0)
3165 *trace_pgfaults |= TRACE_PFMAJ;
3166 else if (strcmp(str, "min") == 0)
3167 *trace_pgfaults |= TRACE_PFMIN;
3168 else
3169 return -1;
3170
3171 return 0;
3172}
3173
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003174static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3175{
3176 struct perf_evsel *evsel;
3177
3178 evlist__for_each(evlist, evsel)
3179 evsel->handler = handler;
3180}
3181
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003182int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3183{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003184 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003185 "perf trace [<options>] [<command>]",
3186 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003187 "perf trace record [<options>] [<command>]",
3188 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003189 NULL
3190 };
3191 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003192 .audit = {
3193 .machine = audit_detect_machine(),
3194 .open_id = audit_name_to_syscall("open", trace.audit.machine),
3195 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003196 .syscalls = {
3197 . max = -1,
3198 },
3199 .opts = {
3200 .target = {
3201 .uid = UINT_MAX,
3202 .uses_mmap = true,
3203 },
3204 .user_freq = UINT_MAX,
3205 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003206 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003207 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003208 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003209 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003210 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003211 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003212 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003213 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003214 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003215 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003216 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003217 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3218 "event selector. use 'perf list' to list available events",
3219 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003220 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3221 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003222 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03003223 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003224 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003225 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003226 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3227 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003228 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003229 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003230 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3231 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003232 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003233 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003234 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003235 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003236 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003237 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003238 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3239 "number of mmap data pages",
3240 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003241 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003242 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003243 OPT_CALLBACK(0, "duration", &trace, "float",
3244 "show only events with duration > N.M ms",
3245 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003246 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003247 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003248 OPT_BOOLEAN('T', "time", &trace.full_time,
3249 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003250 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3251 "Show only syscall summary with statistics"),
3252 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3253 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003254 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3255 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003256 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003257 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003258 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3259 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003260 OPT_END()
3261 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003262 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003263 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003264 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003265
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003266 signal(SIGSEGV, sighandler_dump_stack);
3267 signal(SIGFPE, sighandler_dump_stack);
3268
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003269 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003270
3271 if (trace.evlist == NULL) {
3272 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003273 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003274 goto out;
3275 }
3276
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003277 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3278 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003279
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003280 if (trace.trace_pgfaults) {
3281 trace.opts.sample_address = true;
3282 trace.opts.sample_time = true;
3283 }
3284
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003285 if (trace.evlist->nr_entries > 0)
3286 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3287
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003288 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3289 return trace__record(&trace, argc-1, &argv[1]);
3290
3291 /* summary_only implies summary option, but don't overwrite summary if set */
3292 if (trace.summary_only)
3293 trace.summary = trace.summary_only;
3294
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003295 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3296 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003297 pr_err("Please specify something to trace.\n");
3298 return -1;
3299 }
3300
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003301 if (output_name != NULL) {
3302 err = trace__open_output(&trace, output_name);
3303 if (err < 0) {
3304 perror("failed to create output file");
3305 goto out;
3306 }
3307 }
3308
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003309 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003310 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003311 struct strlist_config slist_config = {
3312 .dirname = system_path(STRACE_GROUPS_DIR),
3313 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003314
3315 trace.not_ev_qualifier = *s == '!';
3316 if (trace.not_ev_qualifier)
3317 ++s;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003318 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003319 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003320 fputs("Not enough memory to parse event qualifier",
3321 trace.output);
3322 err = -ENOMEM;
3323 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003324 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003325
3326 err = trace__validate_ev_qualifier(&trace);
3327 if (err)
3328 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003329 }
3330
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003331 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003332 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003333 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003334 fprintf(trace.output, "%s", bf);
3335 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003336 }
3337
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003338 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003339 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003340 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003341 fprintf(trace.output, "%s", bf);
3342 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003343 }
3344
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003345 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003346 trace.opts.target.system_wide = true;
3347
David Ahern6810fc92013-08-28 22:29:52 -06003348 if (input_name)
3349 err = trace__replay(&trace);
3350 else
3351 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003352
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003353out_close:
3354 if (output_name != NULL)
3355 fclose(trace.output);
3356out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003357 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003358}