blob: 57d4bb473add3b53a3f7dbd0cb7d3016db6c41a6 [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 Meloa3bca912016-04-06 12:51:33 -03001129#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001130#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001131
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001132static struct syscall_fmt {
1133 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001134 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001135 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001136 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001137 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001138 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001139 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001140 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001141} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -03001142 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001143 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1144 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001145 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -03001146 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001147 { .name = "brk", .hexret = true,
1148 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001149 { .name = "chdir", .errmsg = true,
1150 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1151 { .name = "chmod", .errmsg = true,
1152 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1153 { .name = "chroot", .errmsg = true,
1154 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -06001155 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001156 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001157 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001158 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -03001159 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001160 { .name = "creat", .errmsg = true,
1161 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001162 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001163 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001164 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001165 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001166 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001167 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001168 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -03001169 { .name = "eventfd2", .errmsg = true,
1170 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001171 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001172 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1173 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001174 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001175 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001176 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001177 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001178 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001179 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001180 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001181 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001182 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001183 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1184 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001185 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001186 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001187 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001188 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1189 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001190 { .name = "fcntl", .errmsg = true,
1191 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1192 [1] = SCA_STRARRAY, /* cmd */ },
1193 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1194 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001195 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -03001196 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001197 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1198 [1] = SCA_FLOCK, /* cmd */ }, },
1199 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001200 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001201 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001202 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001203 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001204 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1205 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001206 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001207 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001208 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001209 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001210 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001211 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -03001212 { .name = "futex", .errmsg = true,
1213 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001214 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001215 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1216 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001217 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001218 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001219 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001220 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001221 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001222 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001223 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001224 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -03001225 { .name = "getrandom", .errmsg = true,
1226 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001227 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001228 { .name = "getxattr", .errmsg = true,
1229 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1230 { .name = "inotify_add_watch", .errmsg = true,
1231 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001232 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001233 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001234#if defined(__i386__) || defined(__x86_64__)
1235/*
1236 * FIXME: Make this available to all arches.
1237 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001238 [1] = SCA_STRHEXARRAY, /* cmd */
1239 [2] = SCA_HEX, /* arg */ },
1240 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001241#else
1242 [2] = SCA_HEX, /* arg */ }, },
1243#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -03001244 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001245 { .name = "kill", .errmsg = true,
1246 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001247 { .name = "lchown", .errmsg = true,
1248 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1249 { .name = "lgetxattr", .errmsg = true,
1250 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001251 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001252 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001253 { .name = "listxattr", .errmsg = true,
1254 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001255 { .name = "llistxattr", .errmsg = true,
1256 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1257 { .name = "lremovexattr", .errmsg = true,
1258 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001259 { .name = "lseek", .errmsg = true,
1260 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1261 [2] = SCA_STRARRAY, /* whence */ },
1262 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001263 { .name = "lsetxattr", .errmsg = true,
1264 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001265 { .name = "lstat", .errmsg = true, .alias = "newlstat",
1266 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001267 { .name = "lsxattr", .errmsg = true,
1268 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001269 { .name = "madvise", .errmsg = true,
1270 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1271 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001272 { .name = "mkdir", .errmsg = true,
1273 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001274 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001275 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1276 [1] = SCA_FILENAME, /* pathname */ }, },
1277 { .name = "mknod", .errmsg = true,
1278 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001279 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001280 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1281 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001282 { .name = "mlock", .errmsg = true,
1283 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1284 { .name = "mlockall", .errmsg = true,
1285 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001286 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001287 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001288 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001289 [3] = SCA_MMAP_FLAGS, /* flags */
1290 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001291 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001292 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1293 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001294 { .name = "mq_unlink", .errmsg = true,
1295 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001296 { .name = "mremap", .hexret = true,
1297 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001298 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001299 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001300 { .name = "munlock", .errmsg = true,
1301 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001302 { .name = "munmap", .errmsg = true,
1303 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001304 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001305 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001306 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001307 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1308 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001309 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001310 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1311 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001312 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001313 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1314 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001315 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001316 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001317 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001318 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001319 { .name = "perf_event_open", .errmsg = true,
1320 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1321 [2] = SCA_INT, /* cpu */
1322 [3] = SCA_FD, /* group_fd */
1323 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001324 { .name = "pipe2", .errmsg = true,
1325 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001326 { .name = "poll", .errmsg = true, .timeout = true, },
1327 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001328 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001329 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001330 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001331 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001332 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001333 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001334 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001335 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001336 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001337 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001338 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001339 { .name = "readlink", .errmsg = true,
1340 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001341 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001342 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1343 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001344 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001345 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001346 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001347 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1348 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001349 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001350 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1351 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001352 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001353 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1354 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001355 { .name = "removexattr", .errmsg = true,
1356 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001357 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001358 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001359 { .name = "rmdir", .errmsg = true,
1360 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001361 { .name = "rt_sigaction", .errmsg = true,
1362 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001363 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001364 { .name = "rt_sigqueueinfo", .errmsg = true,
1365 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1366 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1367 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001368 { .name = "sched_setscheduler", .errmsg = true,
1369 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001370 { .name = "seccomp", .errmsg = true,
1371 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
1372 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001373 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001374 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001375 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1376 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001377 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001378 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1379 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001380 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001381 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1382 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001383 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001384 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001385 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001386 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001387 { .name = "setxattr", .errmsg = true,
1388 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001389 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001390 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001391 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001392 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1393 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001394 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001395 { .name = "socketpair", .errmsg = true,
1396 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1397 [1] = SCA_SK_TYPE, /* type */ },
1398 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001399 { .name = "stat", .errmsg = true, .alias = "newstat",
1400 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001401 { .name = "statfs", .errmsg = true,
1402 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1403 { .name = "swapoff", .errmsg = true,
1404 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1405 { .name = "swapon", .errmsg = true,
1406 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001407 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001408 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001409 { .name = "tgkill", .errmsg = true,
1410 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1411 { .name = "tkill", .errmsg = true,
1412 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001413 { .name = "truncate", .errmsg = true,
1414 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001415 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001416 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001417 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1418 [1] = SCA_FILENAME, /* pathname */ }, },
1419 { .name = "utime", .errmsg = true,
1420 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001421 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001422 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1423 [1] = SCA_FILENAME, /* filename */ }, },
1424 { .name = "utimes", .errmsg = true,
1425 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001426 { .name = "vmsplice", .errmsg = true,
1427 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001428 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001429 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001430 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001431 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001432 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001433 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001434 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001435 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001436};
1437
1438static int syscall_fmt__cmp(const void *name, const void *fmtp)
1439{
1440 const struct syscall_fmt *fmt = fmtp;
1441 return strcmp(name, fmt->name);
1442}
1443
1444static struct syscall_fmt *syscall_fmt__find(const char *name)
1445{
1446 const int nmemb = ARRAY_SIZE(syscall_fmts);
1447 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1448}
1449
1450struct syscall {
1451 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001452 int nr_args;
1453 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001454 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001455 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001456 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001457 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001458 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001459};
1460
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001461static size_t fprintf_duration(unsigned long t, FILE *fp)
1462{
1463 double duration = (double)t / NSEC_PER_MSEC;
1464 size_t printed = fprintf(fp, "(");
1465
1466 if (duration >= 1.0)
1467 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1468 else if (duration >= 0.01)
1469 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1470 else
1471 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001472 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001473}
1474
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001475/**
1476 * filename.ptr: The filename char pointer that will be vfs_getname'd
1477 * filename.entry_str_pos: Where to insert the string translated from
1478 * filename.ptr by the vfs_getname tracepoint/kprobe.
1479 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001480struct thread_trace {
1481 u64 entry_time;
1482 u64 exit_time;
1483 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001484 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001485 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001486 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001487 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001488 struct {
1489 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001490 short int entry_str_pos;
1491 bool pending_open;
1492 unsigned int namelen;
1493 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001494 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001495 struct {
1496 int max;
1497 char **table;
1498 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001499
1500 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001501};
1502
1503static struct thread_trace *thread_trace__new(void)
1504{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001505 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1506
1507 if (ttrace)
1508 ttrace->paths.max = -1;
1509
David Ahernbf2575c2013-10-08 21:26:53 -06001510 ttrace->syscall_stats = intlist__new(NULL);
1511
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001512 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001513}
1514
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001515static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001516{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001517 struct thread_trace *ttrace;
1518
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001519 if (thread == NULL)
1520 goto fail;
1521
Namhyung Kim89dceb22014-10-06 09:46:03 +09001522 if (thread__priv(thread) == NULL)
1523 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001524
Namhyung Kim89dceb22014-10-06 09:46:03 +09001525 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001526 goto fail;
1527
Namhyung Kim89dceb22014-10-06 09:46:03 +09001528 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001529 ++ttrace->nr_events;
1530
1531 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001532fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001533 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001534 "WARNING: not enough memory, dropping samples!\n");
1535 return NULL;
1536}
1537
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001538#define TRACE_PFMAJ (1 << 0)
1539#define TRACE_PFMIN (1 << 1)
1540
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001541static const size_t trace__entry_str_size = 2048;
1542
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001543static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001544{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001545 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001546
1547 if (fd > ttrace->paths.max) {
1548 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1549
1550 if (npath == NULL)
1551 return -1;
1552
1553 if (ttrace->paths.max != -1) {
1554 memset(npath + ttrace->paths.max + 1, 0,
1555 (fd - ttrace->paths.max) * sizeof(char *));
1556 } else {
1557 memset(npath, 0, (fd + 1) * sizeof(char *));
1558 }
1559
1560 ttrace->paths.table = npath;
1561 ttrace->paths.max = fd;
1562 }
1563
1564 ttrace->paths.table[fd] = strdup(pathname);
1565
1566 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1567}
1568
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001569static int thread__read_fd_path(struct thread *thread, int fd)
1570{
1571 char linkname[PATH_MAX], pathname[PATH_MAX];
1572 struct stat st;
1573 int ret;
1574
1575 if (thread->pid_ == thread->tid) {
1576 scnprintf(linkname, sizeof(linkname),
1577 "/proc/%d/fd/%d", thread->pid_, fd);
1578 } else {
1579 scnprintf(linkname, sizeof(linkname),
1580 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1581 }
1582
1583 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1584 return -1;
1585
1586 ret = readlink(linkname, pathname, sizeof(pathname));
1587
1588 if (ret < 0 || ret > st.st_size)
1589 return -1;
1590
1591 pathname[ret] = '\0';
1592 return trace__set_fd_pathname(thread, fd, pathname);
1593}
1594
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001595static const char *thread__fd_path(struct thread *thread, int fd,
1596 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001597{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001598 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001599
1600 if (ttrace == NULL)
1601 return NULL;
1602
1603 if (fd < 0)
1604 return NULL;
1605
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001606 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001607 if (!trace->live)
1608 return NULL;
1609 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001610 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001611 return NULL;
1612 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001613
1614 return ttrace->paths.table[fd];
1615}
1616
1617static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1618 struct syscall_arg *arg)
1619{
1620 int fd = arg->val;
1621 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001622 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001623
1624 if (path)
1625 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1626
1627 return printed;
1628}
1629
1630static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1631 struct syscall_arg *arg)
1632{
1633 int fd = arg->val;
1634 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001635 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001636
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001637 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1638 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001639
1640 return printed;
1641}
1642
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001643static void thread__set_filename_pos(struct thread *thread, const char *bf,
1644 unsigned long ptr)
1645{
1646 struct thread_trace *ttrace = thread__priv(thread);
1647
1648 ttrace->filename.ptr = ptr;
1649 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1650}
1651
1652static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1653 struct syscall_arg *arg)
1654{
1655 unsigned long ptr = arg->val;
1656
1657 if (!arg->trace->vfs_getname)
1658 return scnprintf(bf, size, "%#x", ptr);
1659
1660 thread__set_filename_pos(arg->thread, bf, ptr);
1661 return 0;
1662}
1663
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001664static bool trace__filter_duration(struct trace *trace, double t)
1665{
1666 return t < (trace->duration_filter * NSEC_PER_MSEC);
1667}
1668
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001669static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1670{
1671 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1672
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001673 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001674}
1675
Namhyung Kimf15eb532012-10-05 14:02:16 +09001676static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001677static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001678
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001679static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001680{
1681 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001682 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001683}
1684
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001685static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001686 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001687{
1688 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001689 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001690
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001691 if (trace->multiple_threads) {
1692 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001693 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001694 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001695 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001696
1697 return printed;
1698}
1699
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001700static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001701 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001702{
1703 int ret = 0;
1704
1705 switch (event->header.type) {
1706 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001707 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001708 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001709 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001710 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001711 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001712 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001713 break;
1714 }
1715
1716 return ret;
1717}
1718
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001719static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001720 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001721 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001722 struct machine *machine)
1723{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001724 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001725 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001726}
1727
1728static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1729{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001730 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001731
1732 if (err)
1733 return err;
1734
David Ahern8fb598e2013-09-28 13:13:00 -06001735 trace->host = machine__new_host();
1736 if (trace->host == NULL)
1737 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001738
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001739 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001740 return -errno;
1741
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001742 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001743 evlist->threads, trace__tool_process, false,
1744 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001745 if (err)
1746 symbol__exit();
1747
1748 return err;
1749}
1750
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001751static int syscall__set_arg_fmts(struct syscall *sc)
1752{
1753 struct format_field *field;
1754 int idx = 0;
1755
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001756 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001757 if (sc->arg_scnprintf == NULL)
1758 return -1;
1759
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001760 if (sc->fmt)
1761 sc->arg_parm = sc->fmt->arg_parm;
1762
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001763 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001764 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1765 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1766 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001767 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001768 else if (strcmp(field->type, "pid_t") == 0)
1769 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001770 ++idx;
1771 }
1772
1773 return 0;
1774}
1775
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001776static int trace__read_syscall_info(struct trace *trace, int id)
1777{
1778 char tp_name[128];
1779 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001780 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001781
1782 if (name == NULL)
1783 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001784
1785 if (id > trace->syscalls.max) {
1786 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1787
1788 if (nsyscalls == NULL)
1789 return -1;
1790
1791 if (trace->syscalls.max != -1) {
1792 memset(nsyscalls + trace->syscalls.max + 1, 0,
1793 (id - trace->syscalls.max) * sizeof(*sc));
1794 } else {
1795 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1796 }
1797
1798 trace->syscalls.table = nsyscalls;
1799 trace->syscalls.max = id;
1800 }
1801
1802 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001803 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001804
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001805 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001806
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001807 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001808 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001809
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001810 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001811 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001812 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001813 }
1814
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001815 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001816 return -1;
1817
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001818 sc->args = sc->tp_format->format.fields;
1819 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001820 /*
1821 * We need to check and discard the first variable '__syscall_nr'
1822 * or 'nr' that mean the syscall number. It is needless here.
1823 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1824 */
1825 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001826 sc->args = sc->args->next;
1827 --sc->nr_args;
1828 }
1829
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001830 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1831
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001832 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001833}
1834
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001835static int trace__validate_ev_qualifier(struct trace *trace)
1836{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001837 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001838 struct str_node *pos;
1839
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001840 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1841 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1842 sizeof(trace->ev_qualifier_ids.entries[0]));
1843
1844 if (trace->ev_qualifier_ids.entries == NULL) {
1845 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1846 trace->output);
1847 err = -EINVAL;
1848 goto out;
1849 }
1850
1851 i = 0;
1852
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001853 strlist__for_each(pos, trace->ev_qualifier) {
1854 const char *sc = pos->s;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001855 int id = audit_name_to_syscall(sc, trace->audit.machine);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001856
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001857 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001858 if (err == 0) {
1859 fputs("Error:\tInvalid syscall ", trace->output);
1860 err = -EINVAL;
1861 } else {
1862 fputs(", ", trace->output);
1863 }
1864
1865 fputs(sc, trace->output);
1866 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001867
1868 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001869 }
1870
1871 if (err < 0) {
1872 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1873 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001874 zfree(&trace->ev_qualifier_ids.entries);
1875 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001876 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001877out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001878 return err;
1879}
1880
David Ahern55d43bc2015-02-19 15:00:22 -05001881/*
1882 * args is to be interpreted as a series of longs but we need to handle
1883 * 8-byte unaligned accesses. args points to raw_data within the event
1884 * and raw_data is guaranteed to be 8-byte unaligned because it is
1885 * preceded by raw_size which is a u32. So we need to copy args to a temp
1886 * variable to read it. Most notably this avoids extended load instructions
1887 * on unaligned addresses
1888 */
1889
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001890static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001891 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001892 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001893{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001894 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001895 unsigned char *p;
1896 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001897
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001898 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001899 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001900 u8 bit = 1;
1901 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001902 .idx = 0,
1903 .mask = 0,
1904 .trace = trace,
1905 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001906 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001907
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001908 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001909 field = field->next, ++arg.idx, bit <<= 1) {
1910 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001911 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001912
1913 /* special care for unaligned accesses */
1914 p = args + sizeof(unsigned long) * arg.idx;
1915 memcpy(&val, p, sizeof(val));
1916
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001917 /*
1918 * Suppress this argument if its value is zero and
1919 * and we don't have a string associated in an
1920 * strarray for it.
1921 */
David Ahern55d43bc2015-02-19 15:00:22 -05001922 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001923 !(sc->arg_scnprintf &&
1924 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1925 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001926 continue;
1927
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001928 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001929 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001930 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001931 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001932 if (sc->arg_parm)
1933 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001934 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1935 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001936 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001937 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001938 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001939 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001940 }
1941 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001942 int i = 0;
1943
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001944 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001945 /* special care for unaligned accesses */
1946 p = args + sizeof(unsigned long) * i;
1947 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001948 printed += scnprintf(bf + printed, size - printed,
1949 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001950 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001951 ++i;
1952 }
1953 }
1954
1955 return printed;
1956}
1957
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001958typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001959 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001960 struct perf_sample *sample);
1961
1962static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001963 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001964{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001965
1966 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001967
1968 /*
1969 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1970 * before that, leaving at a higher verbosity level till that is
1971 * explained. Reproduced with plain ftrace with:
1972 *
1973 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1974 * grep "NR -1 " /t/trace_pipe
1975 *
1976 * After generating some load on the machine.
1977 */
1978 if (verbose > 1) {
1979 static u64 n;
1980 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1981 id, perf_evsel__name(evsel), ++n);
1982 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001983 return NULL;
1984 }
1985
1986 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1987 trace__read_syscall_info(trace, id))
1988 goto out_cant_read;
1989
1990 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1991 goto out_cant_read;
1992
1993 return &trace->syscalls.table[id];
1994
1995out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001996 if (verbose) {
1997 fprintf(trace->output, "Problems reading syscall %d", id);
1998 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1999 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
2000 fputs(" information\n", trace->output);
2001 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002002 return NULL;
2003}
2004
David Ahernbf2575c2013-10-08 21:26:53 -06002005static void thread__update_stats(struct thread_trace *ttrace,
2006 int id, struct perf_sample *sample)
2007{
2008 struct int_node *inode;
2009 struct stats *stats;
2010 u64 duration = 0;
2011
2012 inode = intlist__findnew(ttrace->syscall_stats, id);
2013 if (inode == NULL)
2014 return;
2015
2016 stats = inode->priv;
2017 if (stats == NULL) {
2018 stats = malloc(sizeof(struct stats));
2019 if (stats == NULL)
2020 return;
2021 init_stats(stats);
2022 inode->priv = stats;
2023 }
2024
2025 if (ttrace->entry_time && sample->time > ttrace->entry_time)
2026 duration = sample->time - ttrace->entry_time;
2027
2028 update_stats(stats, duration);
2029}
2030
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03002031static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
2032{
2033 struct thread_trace *ttrace;
2034 u64 duration;
2035 size_t printed;
2036
2037 if (trace->current == NULL)
2038 return 0;
2039
2040 ttrace = thread__priv(trace->current);
2041
2042 if (!ttrace->entry_pending)
2043 return 0;
2044
2045 duration = sample->time - ttrace->entry_time;
2046
2047 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
2048 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
2049 ttrace->entry_pending = false;
2050
2051 return printed;
2052}
2053
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002054static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002055 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002056 struct perf_sample *sample)
2057{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002058 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002059 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002060 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002061 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002062 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002063 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002064 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002065
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002066 if (sc == NULL)
2067 return -1;
2068
David Ahern8fb598e2013-09-28 13:13:00 -06002069 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002070 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002071 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002072 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002073
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002074 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002075
2076 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002077 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002078 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002079 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002080 }
2081
David Ahern13f22a22015-03-19 12:23:03 -06002082 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03002083 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03002084
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002085 ttrace->entry_time = sample->time;
2086 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002087 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002088
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002089 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002090 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002091
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03002092 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07002093 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002094 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
2095 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002096 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002097 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002098 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002099 /* See trace__vfs_getname & trace__sys_exit */
2100 ttrace->filename.pending_open = false;
2101 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002102
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002103 if (trace->current != thread) {
2104 thread__put(trace->current);
2105 trace->current = thread__get(thread);
2106 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002107 err = 0;
2108out_put:
2109 thread__put(thread);
2110 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002111}
2112
2113static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002114 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002115 struct perf_sample *sample)
2116{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002117 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002118 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002119 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002120 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002121 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002122 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002123
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002124 if (sc == NULL)
2125 return -1;
2126
David Ahern8fb598e2013-09-28 13:13:00 -06002127 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002128 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002129 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002130 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002131
David Ahernbf2575c2013-10-08 21:26:53 -06002132 if (trace->summary)
2133 thread__update_stats(ttrace, id, sample);
2134
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002135 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002136
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002137 if (id == trace->audit.open_id && ret >= 0 && ttrace->filename.pending_open) {
2138 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
2139 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002140 ++trace->stats.vfs_getname;
2141 }
2142
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002143 ttrace->exit_time = sample->time;
2144
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002145 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002146 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002147 if (trace__filter_duration(trace, duration))
2148 goto out;
2149 } else if (trace->duration_filter)
2150 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002151
David Ahernfd2eaba2013-11-12 09:31:15 -07002152 if (trace->summary_only)
2153 goto out;
2154
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002155 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002156
2157 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002158 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002159 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002160 fprintf(trace->output, " ... [");
2161 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
2162 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002163 }
2164
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002165 if (sc->fmt == NULL) {
2166signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002167 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03002168 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00002169 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002170 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
2171 *e = audit_errno_to_name(-ret);
2172
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002173 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002174 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002175 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03002176 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002177 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03002178 else if (sc->fmt->errpid) {
2179 struct thread *child = machine__find_thread(trace->host, ret, ret);
2180
2181 if (child != NULL) {
2182 fprintf(trace->output, ") = %ld", ret);
2183 if (child->comm_set)
2184 fprintf(trace->output, " (%s)", thread__comm_str(child));
2185 thread__put(child);
2186 }
2187 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002188 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002189
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002190 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002191out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002192 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002193 err = 0;
2194out_put:
2195 thread__put(thread);
2196 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002197}
2198
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002199static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002200 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002201 struct perf_sample *sample)
2202{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002203 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2204 struct thread_trace *ttrace;
2205 size_t filename_len, entry_str_len, to_move;
2206 ssize_t remaining_space;
2207 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002208 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002209
2210 if (!thread)
2211 goto out;
2212
2213 ttrace = thread__priv(thread);
2214 if (!ttrace)
2215 goto out;
2216
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002217 filename_len = strlen(filename);
2218
2219 if (ttrace->filename.namelen < filename_len) {
2220 char *f = realloc(ttrace->filename.name, filename_len + 1);
2221
2222 if (f == NULL)
2223 goto out;
2224
2225 ttrace->filename.namelen = filename_len;
2226 ttrace->filename.name = f;
2227 }
2228
2229 strcpy(ttrace->filename.name, filename);
2230 ttrace->filename.pending_open = true;
2231
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002232 if (!ttrace->filename.ptr)
2233 goto out;
2234
2235 entry_str_len = strlen(ttrace->entry_str);
2236 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2237 if (remaining_space <= 0)
2238 goto out;
2239
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002240 if (filename_len > (size_t)remaining_space) {
2241 filename += filename_len - remaining_space;
2242 filename_len = remaining_space;
2243 }
2244
2245 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2246 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2247 memmove(pos + filename_len, pos, to_move);
2248 memcpy(pos, filename, filename_len);
2249
2250 ttrace->filename.ptr = 0;
2251 ttrace->filename.entry_str_pos = 0;
2252out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002253 return 0;
2254}
2255
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002256static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002257 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002258 struct perf_sample *sample)
2259{
2260 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2261 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06002262 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03002263 sample->pid,
2264 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002265 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002266
2267 if (ttrace == NULL)
2268 goto out_dump;
2269
2270 ttrace->runtime_ms += runtime_ms;
2271 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002272 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002273 return 0;
2274
2275out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002276 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002277 evsel->name,
2278 perf_evsel__strval(evsel, sample, "comm"),
2279 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2280 runtime,
2281 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002282 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002283 return 0;
2284}
2285
Wang Nan1d6c9402016-02-26 09:31:55 +00002286static void bpf_output__printer(enum binary_printer_ops op,
2287 unsigned int val, void *extra)
2288{
2289 FILE *output = extra;
2290 unsigned char ch = (unsigned char)val;
2291
2292 switch (op) {
2293 case BINARY_PRINT_CHAR_DATA:
2294 fprintf(output, "%c", isprint(ch) ? ch : '.');
2295 break;
2296 case BINARY_PRINT_DATA_BEGIN:
2297 case BINARY_PRINT_LINE_BEGIN:
2298 case BINARY_PRINT_ADDR:
2299 case BINARY_PRINT_NUM_DATA:
2300 case BINARY_PRINT_NUM_PAD:
2301 case BINARY_PRINT_SEP:
2302 case BINARY_PRINT_CHAR_PAD:
2303 case BINARY_PRINT_LINE_END:
2304 case BINARY_PRINT_DATA_END:
2305 default:
2306 break;
2307 }
2308}
2309
2310static void bpf_output__fprintf(struct trace *trace,
2311 struct perf_sample *sample)
2312{
2313 print_binary(sample->raw_data, sample->raw_size, 8,
2314 bpf_output__printer, trace->output);
2315}
2316
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002317static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2318 union perf_event *event __maybe_unused,
2319 struct perf_sample *sample)
2320{
2321 trace__printf_interrupted_entry(trace, sample);
2322 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002323
2324 if (trace->trace_syscalls)
2325 fprintf(trace->output, "( ): ");
2326
2327 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002328
Wang Nan1d6c9402016-02-26 09:31:55 +00002329 if (perf_evsel__is_bpf_output(evsel)) {
2330 bpf_output__fprintf(trace, sample);
2331 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002332 event_format__fprintf(evsel->tp_format, sample->cpu,
2333 sample->raw_data, sample->raw_size,
2334 trace->output);
2335 }
2336
2337 fprintf(trace->output, ")\n");
2338 return 0;
2339}
2340
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002341static void print_location(FILE *f, struct perf_sample *sample,
2342 struct addr_location *al,
2343 bool print_dso, bool print_sym)
2344{
2345
2346 if ((verbose || print_dso) && al->map)
2347 fprintf(f, "%s@", al->map->dso->long_name);
2348
2349 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002350 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002351 al->addr - al->sym->start);
2352 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002353 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002354 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002355 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002356}
2357
2358static int trace__pgfault(struct trace *trace,
2359 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002360 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002361 struct perf_sample *sample)
2362{
2363 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002364 struct addr_location al;
2365 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002366 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002367 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002368
2369 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002370 ttrace = thread__trace(thread, trace->output);
2371 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002372 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002373
2374 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2375 ttrace->pfmaj++;
2376 else
2377 ttrace->pfmin++;
2378
2379 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002380 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002381
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002382 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002383 sample->ip, &al);
2384
2385 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2386
2387 fprintf(trace->output, "%sfault [",
2388 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2389 "maj" : "min");
2390
2391 print_location(trace->output, sample, &al, false, true);
2392
2393 fprintf(trace->output, "] => ");
2394
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002395 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002396 sample->addr, &al);
2397
2398 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002399 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002400 MAP__FUNCTION, sample->addr, &al);
2401
2402 if (al.map)
2403 map_type = 'x';
2404 else
2405 map_type = '?';
2406 }
2407
2408 print_location(trace->output, sample, &al, true, false);
2409
2410 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002411out:
2412 err = 0;
2413out_put:
2414 thread__put(thread);
2415 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002416}
2417
David Ahernbdc89662013-08-28 22:29:53 -06002418static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2419{
2420 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2421 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2422 return false;
2423
2424 if (trace->pid_list || trace->tid_list)
2425 return true;
2426
2427 return false;
2428}
2429
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002430static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002431 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002432 struct perf_sample *sample)
2433{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002434 /*
2435 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2436 * and don't use sample->time unconditionally, we may end up having
2437 * some other event in the future without PERF_SAMPLE_TIME for good
2438 * reason, i.e. we may not be interested in its timestamps, just in
2439 * it taking place, picking some piece of information when it
2440 * appears in our event stream (vfs_getname comes to mind).
2441 */
2442 if (trace->base_time == 0 && !trace->full_time &&
2443 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002444 trace->base_time = sample->time;
2445}
2446
David Ahern6810fc92013-08-28 22:29:52 -06002447static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002448 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002449 struct perf_sample *sample,
2450 struct perf_evsel *evsel,
2451 struct machine *machine __maybe_unused)
2452{
2453 struct trace *trace = container_of(tool, struct trace, tool);
2454 int err = 0;
2455
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002456 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002457
David Ahernbdc89662013-08-28 22:29:53 -06002458 if (skip_sample(trace, sample))
2459 return 0;
2460
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002461 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002462
David Ahern31605652013-12-04 19:41:41 -07002463 if (handler) {
2464 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002465 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002466 }
David Ahern6810fc92013-08-28 22:29:52 -06002467
2468 return err;
2469}
2470
David Ahernbdc89662013-08-28 22:29:53 -06002471static int parse_target_str(struct trace *trace)
2472{
2473 if (trace->opts.target.pid) {
2474 trace->pid_list = intlist__new(trace->opts.target.pid);
2475 if (trace->pid_list == NULL) {
2476 pr_err("Error parsing process id string\n");
2477 return -EINVAL;
2478 }
2479 }
2480
2481 if (trace->opts.target.tid) {
2482 trace->tid_list = intlist__new(trace->opts.target.tid);
2483 if (trace->tid_list == NULL) {
2484 pr_err("Error parsing thread id string\n");
2485 return -EINVAL;
2486 }
2487 }
2488
2489 return 0;
2490}
2491
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002492static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002493{
2494 unsigned int rec_argc, i, j;
2495 const char **rec_argv;
2496 const char * const record_args[] = {
2497 "record",
2498 "-R",
2499 "-m", "1024",
2500 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002501 };
2502
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002503 const char * const sc_args[] = { "-e", };
2504 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2505 const char * const majpf_args[] = { "-e", "major-faults" };
2506 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2507 const char * const minpf_args[] = { "-e", "minor-faults" };
2508 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2509
David Ahern9aca7f12013-12-04 19:41:39 -07002510 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002511 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2512 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002513 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2514
2515 if (rec_argv == NULL)
2516 return -ENOMEM;
2517
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002518 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002519 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002520 rec_argv[j++] = record_args[i];
2521
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002522 if (trace->trace_syscalls) {
2523 for (i = 0; i < sc_args_nr; i++)
2524 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002525
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002526 /* event string may be different for older kernels - e.g., RHEL6 */
2527 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2528 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2529 else if (is_valid_tracepoint("syscalls:sys_enter"))
2530 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2531 else {
2532 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2533 return -1;
2534 }
David Ahern9aca7f12013-12-04 19:41:39 -07002535 }
David Ahern9aca7f12013-12-04 19:41:39 -07002536
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002537 if (trace->trace_pgfaults & TRACE_PFMAJ)
2538 for (i = 0; i < majpf_args_nr; i++)
2539 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002540
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002541 if (trace->trace_pgfaults & TRACE_PFMIN)
2542 for (i = 0; i < minpf_args_nr; i++)
2543 rec_argv[j++] = minpf_args[i];
2544
2545 for (i = 0; i < (unsigned int)argc; i++)
2546 rec_argv[j++] = argv[i];
2547
2548 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002549}
2550
David Ahernbf2575c2013-10-08 21:26:53 -06002551static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2552
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002553static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002554{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002555 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002556
2557 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002558 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002559
2560 if (perf_evsel__field(evsel, "pathname") == NULL) {
2561 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002562 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002563 }
2564
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002565 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002566 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002567 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002568}
2569
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002570static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2571 u64 config)
2572{
2573 struct perf_evsel *evsel;
2574 struct perf_event_attr attr = {
2575 .type = PERF_TYPE_SOFTWARE,
2576 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002577 };
2578
2579 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002580 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002581
2582 event_attr_init(&attr);
2583
2584 evsel = perf_evsel__new(&attr);
2585 if (!evsel)
2586 return -ENOMEM;
2587
2588 evsel->handler = trace__pgfault;
2589 perf_evlist__add(evlist, evsel);
2590
2591 return 0;
2592}
2593
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002594static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2595{
2596 const u32 type = event->header.type;
2597 struct perf_evsel *evsel;
2598
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002599 if (type != PERF_RECORD_SAMPLE) {
2600 trace__process_event(trace, trace->host, event, sample);
2601 return;
2602 }
2603
2604 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2605 if (evsel == NULL) {
2606 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2607 return;
2608 }
2609
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002610 trace__set_base_time(trace, evsel, sample);
2611
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002612 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2613 sample->raw_data == NULL) {
2614 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2615 perf_evsel__name(evsel), sample->tid,
2616 sample->cpu, sample->raw_size);
2617 } else {
2618 tracepoint_handler handler = evsel->handler;
2619 handler(trace, evsel, event, sample);
2620 }
2621}
2622
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002623static int trace__add_syscall_newtp(struct trace *trace)
2624{
2625 int ret = -1;
2626 struct perf_evlist *evlist = trace->evlist;
2627 struct perf_evsel *sys_enter, *sys_exit;
2628
2629 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2630 if (sys_enter == NULL)
2631 goto out;
2632
2633 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2634 goto out_delete_sys_enter;
2635
2636 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2637 if (sys_exit == NULL)
2638 goto out_delete_sys_enter;
2639
2640 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2641 goto out_delete_sys_exit;
2642
2643 perf_evlist__add(evlist, sys_enter);
2644 perf_evlist__add(evlist, sys_exit);
2645
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002646 trace->syscalls.events.sys_enter = sys_enter;
2647 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002648
2649 ret = 0;
2650out:
2651 return ret;
2652
2653out_delete_sys_exit:
2654 perf_evsel__delete_priv(sys_exit);
2655out_delete_sys_enter:
2656 perf_evsel__delete_priv(sys_enter);
2657 goto out;
2658}
2659
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002660static int trace__set_ev_qualifier_filter(struct trace *trace)
2661{
2662 int err = -1;
2663 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2664 trace->ev_qualifier_ids.nr,
2665 trace->ev_qualifier_ids.entries);
2666
2667 if (filter == NULL)
2668 goto out_enomem;
2669
2670 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2671 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2672
2673 free(filter);
2674out:
2675 return err;
2676out_enomem:
2677 errno = ENOMEM;
2678 goto out;
2679}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002680
Namhyung Kimf15eb532012-10-05 14:02:16 +09002681static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002682{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002683 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002684 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002685 int err = -1, i;
2686 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002687 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002688 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002689
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002690 trace->live = true;
2691
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002692 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002693 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002694
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002695 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002696 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002697
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002698 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002699 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002700 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002701 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002702
2703 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2704 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002705 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002706
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002707 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002708 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2709 trace__sched_stat_runtime))
2710 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002711
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002712 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2713 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002714 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002715 goto out_delete_evlist;
2716 }
2717
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002718 err = trace__symbols_init(trace, evlist);
2719 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002720 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002721 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002722 }
2723
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002724 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002725
Namhyung Kimf15eb532012-10-05 14:02:16 +09002726 signal(SIGCHLD, sig_handler);
2727 signal(SIGINT, sig_handler);
2728
2729 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002730 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002731 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002732 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002733 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002734 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002735 }
2736 }
2737
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002738 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002739 if (err < 0)
2740 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002741
Wang Nanba504232016-02-26 09:31:54 +00002742 err = bpf__apply_obj_config();
2743 if (err) {
2744 char errbuf[BUFSIZ];
2745
2746 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2747 pr_err("ERROR: Apply config to BPF failed: %s\n",
2748 errbuf);
2749 goto out_error_open;
2750 }
2751
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002752 /*
2753 * Better not use !target__has_task() here because we need to cover the
2754 * case where no threads were specified in the command line, but a
2755 * workload was, and in that case we will fill in the thread_map when
2756 * we fork the workload in perf_evlist__prepare_workload.
2757 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002758 if (trace->filter_pids.nr > 0)
2759 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002760 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002761 err = perf_evlist__set_filter_pid(evlist, getpid());
2762
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002763 if (err < 0)
2764 goto out_error_mem;
2765
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002766 if (trace->ev_qualifier_ids.nr > 0) {
2767 err = trace__set_ev_qualifier_filter(trace);
2768 if (err < 0)
2769 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002770
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002771 pr_debug("event qualifier tracepoint filter: %s\n",
2772 trace->syscalls.events.sys_exit->filter);
2773 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002774
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002775 err = perf_evlist__apply_filters(evlist, &evsel);
2776 if (err < 0)
2777 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002778
Jiri Olsaf8850372013-11-28 17:57:22 +01002779 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002780 if (err < 0)
2781 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002782
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002783 if (!target__none(&trace->opts.target))
2784 perf_evlist__enable(evlist);
2785
Namhyung Kimf15eb532012-10-05 14:02:16 +09002786 if (forks)
2787 perf_evlist__start_workload(evlist);
2788
Jiri Olsae13798c2015-06-23 00:36:02 +02002789 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002790 evlist->threads->nr > 1 ||
2791 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002792again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002793 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002794
2795 for (i = 0; i < evlist->nr_mmaps; i++) {
2796 union perf_event *event;
2797
2798 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002799 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002800
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002801 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002802
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002803 err = perf_evlist__parse_sample(evlist, event, &sample);
2804 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002805 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002806 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002807 }
2808
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002809 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002810next_event:
2811 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002812
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002813 if (interrupted)
2814 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002815
2816 if (done && !draining) {
2817 perf_evlist__disable(evlist);
2818 draining = true;
2819 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002820 }
2821 }
2822
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002823 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002824 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002825
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002826 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2827 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2828 draining = true;
2829
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002830 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002831 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002832 } else {
2833 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002834 }
2835
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002836out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002837 thread__zput(trace->current);
2838
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002839 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002840
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002841 if (!err) {
2842 if (trace->summary)
2843 trace__fprintf_thread_summary(trace, trace->output);
2844
2845 if (trace->show_tool_stats) {
2846 fprintf(trace->output, "Stats:\n "
2847 " vfs_getname : %" PRIu64 "\n"
2848 " proc_getname: %" PRIu64 "\n",
2849 trace->stats.vfs_getname,
2850 trace->stats.proc_getname);
2851 }
2852 }
David Ahernbf2575c2013-10-08 21:26:53 -06002853
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002854out_delete_evlist:
2855 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002856 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002857 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002858 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002859{
2860 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002861
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002862out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002863 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002864 goto out_error;
2865
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002866out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002867 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002868 goto out_error;
2869
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002870out_error_mmap:
2871 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2872 goto out_error;
2873
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002874out_error_open:
2875 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2876
2877out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002878 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302879 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002880
2881out_error_apply_filters:
2882 fprintf(trace->output,
2883 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2884 evsel->filter, perf_evsel__name(evsel), errno,
2885 strerror_r(errno, errbuf, sizeof(errbuf)));
2886 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002887}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002888out_error_mem:
2889 fprintf(trace->output, "Not enough memory to run!\n");
2890 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002891
2892out_errno:
2893 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2894 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002895}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002896
David Ahern6810fc92013-08-28 22:29:52 -06002897static int trace__replay(struct trace *trace)
2898{
2899 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002900 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002901 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002902 struct perf_data_file file = {
2903 .path = input_name,
2904 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002905 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002906 };
David Ahern6810fc92013-08-28 22:29:52 -06002907 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002908 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002909 int err = -1;
2910
2911 trace->tool.sample = trace__process_sample;
2912 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002913 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002914 trace->tool.comm = perf_event__process_comm;
2915 trace->tool.exit = perf_event__process_exit;
2916 trace->tool.fork = perf_event__process_fork;
2917 trace->tool.attr = perf_event__process_attr;
2918 trace->tool.tracing_data = perf_event__process_tracing_data;
2919 trace->tool.build_id = perf_event__process_build_id;
2920
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002921 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002922 trace->tool.ordering_requires_timestamps = true;
2923
2924 /* add tid to output */
2925 trace->multiple_threads = true;
2926
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002927 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002928 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002929 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002930
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002931 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002932 goto out;
2933
David Ahern8fb598e2013-09-28 13:13:00 -06002934 trace->host = &session->machines.host;
2935
David Ahern6810fc92013-08-28 22:29:52 -06002936 err = perf_session__set_tracepoints_handlers(session, handlers);
2937 if (err)
2938 goto out;
2939
Namhyung Kim003824e2013-11-12 15:25:00 +09002940 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2941 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002942 /* older kernels have syscalls tp versus raw_syscalls */
2943 if (evsel == NULL)
2944 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2945 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002946
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002947 if (evsel &&
2948 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2949 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002950 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2951 goto out;
2952 }
2953
2954 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2955 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002956 if (evsel == NULL)
2957 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2958 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002959 if (evsel &&
2960 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2961 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002962 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002963 goto out;
2964 }
2965
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002966 evlist__for_each(session->evlist, evsel) {
2967 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2968 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2969 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2970 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2971 evsel->handler = trace__pgfault;
2972 }
2973
David Ahernbdc89662013-08-28 22:29:53 -06002974 err = parse_target_str(trace);
2975 if (err != 0)
2976 goto out;
2977
David Ahern6810fc92013-08-28 22:29:52 -06002978 setup_pager();
2979
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002980 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002981 if (err)
2982 pr_err("Failed to process events, error %d", err);
2983
David Ahernbf2575c2013-10-08 21:26:53 -06002984 else if (trace->summary)
2985 trace__fprintf_thread_summary(trace, trace->output);
2986
David Ahern6810fc92013-08-28 22:29:52 -06002987out:
2988 perf_session__delete(session);
2989
2990 return err;
2991}
2992
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002993static size_t trace__fprintf_threads_header(FILE *fp)
2994{
2995 size_t printed;
2996
Pekka Enberg99ff7152013-11-12 16:42:14 +02002997 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002998
2999 return printed;
3000}
3001
3002static size_t thread__dump_stats(struct thread_trace *ttrace,
3003 struct trace *trace, FILE *fp)
3004{
3005 struct stats *stats;
3006 size_t printed = 0;
3007 struct syscall *sc;
3008 struct int_node *inode = intlist__first(ttrace->syscall_stats);
3009
3010 if (inode == NULL)
3011 return 0;
3012
3013 printed += fprintf(fp, "\n");
3014
Milian Wolff834fd462015-08-06 11:24:29 +02003015 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
3016 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
3017 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02003018
David Ahernbf2575c2013-10-08 21:26:53 -06003019 /* each int_node is a syscall */
3020 while (inode) {
3021 stats = inode->priv;
3022 if (stats) {
3023 double min = (double)(stats->min) / NSEC_PER_MSEC;
3024 double max = (double)(stats->max) / NSEC_PER_MSEC;
3025 double avg = avg_stats(stats);
3026 double pct;
3027 u64 n = (u64) stats->n;
3028
3029 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
3030 avg /= NSEC_PER_MSEC;
3031
3032 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02003033 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02003034 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
3035 n, avg * n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02003036 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06003037 }
3038
3039 inode = intlist__next(inode);
3040 }
3041
3042 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003043
3044 return printed;
3045}
3046
David Ahern896cbb52013-09-28 13:12:59 -06003047/* struct used to pass data to per-thread function */
3048struct summary_data {
3049 FILE *fp;
3050 struct trace *trace;
3051 size_t printed;
3052};
3053
3054static int trace__fprintf_one_thread(struct thread *thread, void *priv)
3055{
3056 struct summary_data *data = priv;
3057 FILE *fp = data->fp;
3058 size_t printed = data->printed;
3059 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09003060 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06003061 double ratio;
3062
3063 if (ttrace == NULL)
3064 return 0;
3065
3066 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
3067
Pekka Enberg15e65c62013-11-14 18:43:30 +02003068 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003069 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02003070 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04003071 if (ttrace->pfmaj)
3072 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
3073 if (ttrace->pfmin)
3074 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003075 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06003076 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06003077
3078 data->printed += printed;
3079
3080 return 0;
3081}
3082
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003083static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
3084{
David Ahern896cbb52013-09-28 13:12:59 -06003085 struct summary_data data = {
3086 .fp = fp,
3087 .trace = trace
3088 };
3089 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003090
David Ahern896cbb52013-09-28 13:12:59 -06003091 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003092
David Ahern896cbb52013-09-28 13:12:59 -06003093 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003094}
3095
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003096static int trace__set_duration(const struct option *opt, const char *str,
3097 int unset __maybe_unused)
3098{
3099 struct trace *trace = opt->value;
3100
3101 trace->duration_filter = atof(str);
3102 return 0;
3103}
3104
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08003105static int trace__set_filter_pids(const struct option *opt, const char *str,
3106 int unset __maybe_unused)
3107{
3108 int ret = -1;
3109 size_t i;
3110 struct trace *trace = opt->value;
3111 /*
3112 * FIXME: introduce a intarray class, plain parse csv and create a
3113 * { int nr, int entries[] } struct...
3114 */
3115 struct intlist *list = intlist__new(str);
3116
3117 if (list == NULL)
3118 return -1;
3119
3120 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
3121 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
3122
3123 if (trace->filter_pids.entries == NULL)
3124 goto out;
3125
3126 trace->filter_pids.entries[0] = getpid();
3127
3128 for (i = 1; i < trace->filter_pids.nr; ++i)
3129 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
3130
3131 intlist__delete(list);
3132 ret = 0;
3133out:
3134 return ret;
3135}
3136
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003137static int trace__open_output(struct trace *trace, const char *filename)
3138{
3139 struct stat st;
3140
3141 if (!stat(filename, &st) && st.st_size) {
3142 char oldname[PATH_MAX];
3143
3144 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
3145 unlink(oldname);
3146 rename(filename, oldname);
3147 }
3148
3149 trace->output = fopen(filename, "w");
3150
3151 return trace->output == NULL ? -errno : 0;
3152}
3153
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003154static int parse_pagefaults(const struct option *opt, const char *str,
3155 int unset __maybe_unused)
3156{
3157 int *trace_pgfaults = opt->value;
3158
3159 if (strcmp(str, "all") == 0)
3160 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
3161 else if (strcmp(str, "maj") == 0)
3162 *trace_pgfaults |= TRACE_PFMAJ;
3163 else if (strcmp(str, "min") == 0)
3164 *trace_pgfaults |= TRACE_PFMIN;
3165 else
3166 return -1;
3167
3168 return 0;
3169}
3170
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003171static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3172{
3173 struct perf_evsel *evsel;
3174
3175 evlist__for_each(evlist, evsel)
3176 evsel->handler = handler;
3177}
3178
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003179int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3180{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003181 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003182 "perf trace [<options>] [<command>]",
3183 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003184 "perf trace record [<options>] [<command>]",
3185 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003186 NULL
3187 };
3188 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003189 .audit = {
3190 .machine = audit_detect_machine(),
3191 .open_id = audit_name_to_syscall("open", trace.audit.machine),
3192 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003193 .syscalls = {
3194 . max = -1,
3195 },
3196 .opts = {
3197 .target = {
3198 .uid = UINT_MAX,
3199 .uses_mmap = true,
3200 },
3201 .user_freq = UINT_MAX,
3202 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003203 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003204 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003205 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003206 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003207 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003208 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003209 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003210 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003211 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003212 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003213 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003214 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3215 "event selector. use 'perf list' to list available events",
3216 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003217 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3218 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003219 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03003220 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003221 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003222 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003223 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3224 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003225 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003226 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003227 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3228 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003229 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003230 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003231 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003232 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003233 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003234 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003235 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3236 "number of mmap data pages",
3237 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003238 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003239 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003240 OPT_CALLBACK(0, "duration", &trace, "float",
3241 "show only events with duration > N.M ms",
3242 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003243 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003244 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003245 OPT_BOOLEAN('T', "time", &trace.full_time,
3246 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003247 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3248 "Show only syscall summary with statistics"),
3249 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3250 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003251 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3252 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003253 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003254 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003255 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3256 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003257 OPT_END()
3258 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003259 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003260 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003261 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003262
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003263 signal(SIGSEGV, sighandler_dump_stack);
3264 signal(SIGFPE, sighandler_dump_stack);
3265
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003266 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003267
3268 if (trace.evlist == NULL) {
3269 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003270 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003271 goto out;
3272 }
3273
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003274 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3275 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003276
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003277 if (trace.trace_pgfaults) {
3278 trace.opts.sample_address = true;
3279 trace.opts.sample_time = true;
3280 }
3281
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003282 if (trace.evlist->nr_entries > 0)
3283 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3284
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003285 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3286 return trace__record(&trace, argc-1, &argv[1]);
3287
3288 /* summary_only implies summary option, but don't overwrite summary if set */
3289 if (trace.summary_only)
3290 trace.summary = trace.summary_only;
3291
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003292 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3293 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003294 pr_err("Please specify something to trace.\n");
3295 return -1;
3296 }
3297
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003298 if (output_name != NULL) {
3299 err = trace__open_output(&trace, output_name);
3300 if (err < 0) {
3301 perror("failed to create output file");
3302 goto out;
3303 }
3304 }
3305
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003306 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003307 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003308 struct strlist_config slist_config = {
3309 .dirname = system_path(STRACE_GROUPS_DIR),
3310 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003311
3312 trace.not_ev_qualifier = *s == '!';
3313 if (trace.not_ev_qualifier)
3314 ++s;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003315 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003316 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003317 fputs("Not enough memory to parse event qualifier",
3318 trace.output);
3319 err = -ENOMEM;
3320 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003321 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003322
3323 err = trace__validate_ev_qualifier(&trace);
3324 if (err)
3325 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003326 }
3327
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003328 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003329 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003330 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003331 fprintf(trace.output, "%s", bf);
3332 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003333 }
3334
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003335 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003336 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003337 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003338 fprintf(trace.output, "%s", bf);
3339 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003340 }
3341
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003342 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003343 trace.opts.target.system_wide = true;
3344
David Ahern6810fc92013-08-28 22:29:52 -06003345 if (input_name)
3346 err = trace__replay(&trace);
3347 else
3348 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003349
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003350out_close:
3351 if (output_name != NULL)
3352 fclose(trace.output);
3353out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003354 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003355}