blob: c283153d8c7f0475c8af5e69a75574f1641c6444 [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
115
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300116struct tp_field {
117 int offset;
118 union {
119 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
120 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
121 };
122};
123
124#define TP_UINT_FIELD(bits) \
125static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
126{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500127 u##bits value; \
128 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
129 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300130}
131
132TP_UINT_FIELD(8);
133TP_UINT_FIELD(16);
134TP_UINT_FIELD(32);
135TP_UINT_FIELD(64);
136
137#define TP_UINT_FIELD__SWAPPED(bits) \
138static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
139{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500140 u##bits value; \
141 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300142 return bswap_##bits(value);\
143}
144
145TP_UINT_FIELD__SWAPPED(16);
146TP_UINT_FIELD__SWAPPED(32);
147TP_UINT_FIELD__SWAPPED(64);
148
149static int tp_field__init_uint(struct tp_field *field,
150 struct format_field *format_field,
151 bool needs_swap)
152{
153 field->offset = format_field->offset;
154
155 switch (format_field->size) {
156 case 1:
157 field->integer = tp_field__u8;
158 break;
159 case 2:
160 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
161 break;
162 case 4:
163 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
164 break;
165 case 8:
166 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
167 break;
168 default:
169 return -1;
170 }
171
172 return 0;
173}
174
175static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
176{
177 return sample->raw_data + field->offset;
178}
179
180static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
181{
182 field->offset = format_field->offset;
183 field->pointer = tp_field__ptr;
184 return 0;
185}
186
187struct syscall_tp {
188 struct tp_field id;
189 union {
190 struct tp_field args, ret;
191 };
192};
193
194static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
195 struct tp_field *field,
196 const char *name)
197{
198 struct format_field *format_field = perf_evsel__field(evsel, name);
199
200 if (format_field == NULL)
201 return -1;
202
203 return tp_field__init_uint(field, format_field, evsel->needs_swap);
204}
205
206#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
207 ({ struct syscall_tp *sc = evsel->priv;\
208 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
209
210static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
211 struct tp_field *field,
212 const char *name)
213{
214 struct format_field *format_field = perf_evsel__field(evsel, name);
215
216 if (format_field == NULL)
217 return -1;
218
219 return tp_field__init_ptr(field, format_field);
220}
221
222#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
223 ({ struct syscall_tp *sc = evsel->priv;\
224 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
225
226static void perf_evsel__delete_priv(struct perf_evsel *evsel)
227{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300228 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300229 perf_evsel__delete(evsel);
230}
231
Namhyung Kim96695d42013-11-12 08:51:45 -0300232static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
233{
234 evsel->priv = malloc(sizeof(struct syscall_tp));
235 if (evsel->priv != NULL) {
236 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
237 goto out_delete;
238
239 evsel->handler = handler;
240 return 0;
241 }
242
243 return -ENOMEM;
244
245out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300246 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300247 return -ENOENT;
248}
249
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300250static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300251{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300252 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300253
David Ahern9aca7f12013-12-04 19:41:39 -0700254 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200255 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700256 evsel = perf_evsel__newtp("syscalls", direction);
257
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200258 if (IS_ERR(evsel))
259 return NULL;
260
261 if (perf_evsel__init_syscall_tp(evsel, handler))
262 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300263
264 return evsel;
265
266out_delete:
267 perf_evsel__delete_priv(evsel);
268 return NULL;
269}
270
271#define perf_evsel__sc_tp_uint(evsel, name, sample) \
272 ({ struct syscall_tp *fields = evsel->priv; \
273 fields->name.integer(&fields->name, sample); })
274
275#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
276 ({ struct syscall_tp *fields = evsel->priv; \
277 fields->name.pointer(&fields->name, sample); })
278
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300279struct syscall_arg {
280 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300281 struct thread *thread;
282 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300283 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300284 u8 idx;
285 u8 mask;
286};
287
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300288struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300289 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300290 int nr_entries;
291 const char **entries;
292};
293
294#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
295 .nr_entries = ARRAY_SIZE(array), \
296 .entries = array, \
297}
298
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300299#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
300 .offset = off, \
301 .nr_entries = ARRAY_SIZE(array), \
302 .entries = array, \
303}
304
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300305static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
306 const char *intfmt,
307 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300308{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300309 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300310 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300311
312 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300313 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300314
315 return scnprintf(bf, size, "%s", sa->entries[idx]);
316}
317
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300318static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
319 struct syscall_arg *arg)
320{
321 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
322}
323
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300324#define SCA_STRARRAY syscall_arg__scnprintf_strarray
325
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300326#if defined(__i386__) || defined(__x86_64__)
327/*
328 * FIXME: Make this available to all arches as soon as the ioctl beautifier
329 * gets rewritten to support all arches.
330 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300331static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
332 struct syscall_arg *arg)
333{
334 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
335}
336
337#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300338#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300339
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300340static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
341 struct syscall_arg *arg);
342
343#define SCA_FD syscall_arg__scnprintf_fd
344
345static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
346 struct syscall_arg *arg)
347{
348 int fd = arg->val;
349
350 if (fd == AT_FDCWD)
351 return scnprintf(bf, size, "CWD");
352
353 return syscall_arg__scnprintf_fd(bf, size, arg);
354}
355
356#define SCA_FDAT syscall_arg__scnprintf_fd_at
357
358static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
359 struct syscall_arg *arg);
360
361#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
362
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300363static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300364 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300365{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300366 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300367}
368
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300369#define SCA_HEX syscall_arg__scnprintf_hex
370
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300371static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
372 struct syscall_arg *arg)
373{
374 return scnprintf(bf, size, "%d", arg->val);
375}
376
377#define SCA_INT syscall_arg__scnprintf_int
378
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300379static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300380 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300381{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300382 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300383
384 if (prot == PROT_NONE)
385 return scnprintf(bf, size, "NONE");
386#define P_MMAP_PROT(n) \
387 if (prot & PROT_##n) { \
388 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
389 prot &= ~PROT_##n; \
390 }
391
392 P_MMAP_PROT(EXEC);
393 P_MMAP_PROT(READ);
394 P_MMAP_PROT(WRITE);
395#ifdef PROT_SEM
396 P_MMAP_PROT(SEM);
397#endif
398 P_MMAP_PROT(GROWSDOWN);
399 P_MMAP_PROT(GROWSUP);
400#undef P_MMAP_PROT
401
402 if (prot)
403 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
404
405 return printed;
406}
407
408#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
409
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300410static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300411 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300412{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300413 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300414
415#define P_MMAP_FLAG(n) \
416 if (flags & MAP_##n) { \
417 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
418 flags &= ~MAP_##n; \
419 }
420
421 P_MMAP_FLAG(SHARED);
422 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400423#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300424 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400425#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300426 P_MMAP_FLAG(ANONYMOUS);
427 P_MMAP_FLAG(DENYWRITE);
428 P_MMAP_FLAG(EXECUTABLE);
429 P_MMAP_FLAG(FILE);
430 P_MMAP_FLAG(FIXED);
431 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600432#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300433 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600434#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300435 P_MMAP_FLAG(LOCKED);
436 P_MMAP_FLAG(NONBLOCK);
437 P_MMAP_FLAG(NORESERVE);
438 P_MMAP_FLAG(POPULATE);
439 P_MMAP_FLAG(STACK);
440#ifdef MAP_UNINITIALIZED
441 P_MMAP_FLAG(UNINITIALIZED);
442#endif
443#undef P_MMAP_FLAG
444
445 if (flags)
446 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
447
448 return printed;
449}
450
451#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
452
Alex Snast86998dd2014-08-13 18:42:40 +0300453static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
454 struct syscall_arg *arg)
455{
456 int printed = 0, flags = arg->val;
457
458#define P_MREMAP_FLAG(n) \
459 if (flags & MREMAP_##n) { \
460 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
461 flags &= ~MREMAP_##n; \
462 }
463
464 P_MREMAP_FLAG(MAYMOVE);
465#ifdef MREMAP_FIXED
466 P_MREMAP_FLAG(FIXED);
467#endif
468#undef P_MREMAP_FLAG
469
470 if (flags)
471 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
472
473 return printed;
474}
475
476#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
477
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300478static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300479 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300480{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300481 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300482
483 switch (behavior) {
484#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
485 P_MADV_BHV(NORMAL);
486 P_MADV_BHV(RANDOM);
487 P_MADV_BHV(SEQUENTIAL);
488 P_MADV_BHV(WILLNEED);
489 P_MADV_BHV(DONTNEED);
490 P_MADV_BHV(REMOVE);
491 P_MADV_BHV(DONTFORK);
492 P_MADV_BHV(DOFORK);
493 P_MADV_BHV(HWPOISON);
494#ifdef MADV_SOFT_OFFLINE
495 P_MADV_BHV(SOFT_OFFLINE);
496#endif
497 P_MADV_BHV(MERGEABLE);
498 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600499#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300500 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600501#endif
502#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300503 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600504#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300505#ifdef MADV_DONTDUMP
506 P_MADV_BHV(DONTDUMP);
507#endif
508#ifdef MADV_DODUMP
509 P_MADV_BHV(DODUMP);
510#endif
511#undef P_MADV_PHV
512 default: break;
513 }
514
515 return scnprintf(bf, size, "%#x", behavior);
516}
517
518#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
519
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300520static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
521 struct syscall_arg *arg)
522{
523 int printed = 0, op = arg->val;
524
525 if (op == 0)
526 return scnprintf(bf, size, "NONE");
527#define P_CMD(cmd) \
528 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
529 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
530 op &= ~LOCK_##cmd; \
531 }
532
533 P_CMD(SH);
534 P_CMD(EX);
535 P_CMD(NB);
536 P_CMD(UN);
537 P_CMD(MAND);
538 P_CMD(RW);
539 P_CMD(READ);
540 P_CMD(WRITE);
541#undef P_OP
542
543 if (op)
544 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
545
546 return printed;
547}
548
549#define SCA_FLOCK syscall_arg__scnprintf_flock
550
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300551static 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 -0300552{
553 enum syscall_futex_args {
554 SCF_UADDR = (1 << 0),
555 SCF_OP = (1 << 1),
556 SCF_VAL = (1 << 2),
557 SCF_TIMEOUT = (1 << 3),
558 SCF_UADDR2 = (1 << 4),
559 SCF_VAL3 = (1 << 5),
560 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300561 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300562 int cmd = op & FUTEX_CMD_MASK;
563 size_t printed = 0;
564
565 switch (cmd) {
566#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300567 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
568 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
569 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
570 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
571 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
572 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300573 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300574 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
575 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
576 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
577 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
578 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300579 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
580 default: printed = scnprintf(bf, size, "%#x", cmd); break;
581 }
582
583 if (op & FUTEX_PRIVATE_FLAG)
584 printed += scnprintf(bf + printed, size - printed, "|PRIV");
585
586 if (op & FUTEX_CLOCK_REALTIME)
587 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
588
589 return printed;
590}
591
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300592#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
593
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300594static const char *bpf_cmd[] = {
595 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
596 "MAP_GET_NEXT_KEY", "PROG_LOAD",
597};
598static DEFINE_STRARRAY(bpf_cmd);
599
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300600static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
601static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300602
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300603static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
604static DEFINE_STRARRAY(itimers);
605
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300606static const char *keyctl_options[] = {
607 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
608 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
609 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
610 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
611 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
612};
613static DEFINE_STRARRAY(keyctl_options);
614
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300615static const char *whences[] = { "SET", "CUR", "END",
616#ifdef SEEK_DATA
617"DATA",
618#endif
619#ifdef SEEK_HOLE
620"HOLE",
621#endif
622};
623static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300624
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300625static const char *fcntl_cmds[] = {
626 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
627 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
628 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
629 "F_GETOWNER_UIDS",
630};
631static DEFINE_STRARRAY(fcntl_cmds);
632
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300633static const char *rlimit_resources[] = {
634 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
635 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
636 "RTTIME",
637};
638static DEFINE_STRARRAY(rlimit_resources);
639
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300640static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
641static DEFINE_STRARRAY(sighow);
642
David Ahern4f8c1b72013-09-22 19:45:00 -0600643static const char *clockid[] = {
644 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300645 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
646 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600647};
648static DEFINE_STRARRAY(clockid);
649
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300650static const char *socket_families[] = {
651 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
652 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
653 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
654 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
655 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
656 "ALG", "NFC", "VSOCK",
657};
658static DEFINE_STRARRAY(socket_families);
659
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300660#ifndef SOCK_TYPE_MASK
661#define SOCK_TYPE_MASK 0xf
662#endif
663
664static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
665 struct syscall_arg *arg)
666{
667 size_t printed;
668 int type = arg->val,
669 flags = type & ~SOCK_TYPE_MASK;
670
671 type &= SOCK_TYPE_MASK;
672 /*
673 * Can't use a strarray, MIPS may override for ABI reasons.
674 */
675 switch (type) {
676#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
677 P_SK_TYPE(STREAM);
678 P_SK_TYPE(DGRAM);
679 P_SK_TYPE(RAW);
680 P_SK_TYPE(RDM);
681 P_SK_TYPE(SEQPACKET);
682 P_SK_TYPE(DCCP);
683 P_SK_TYPE(PACKET);
684#undef P_SK_TYPE
685 default:
686 printed = scnprintf(bf, size, "%#x", type);
687 }
688
689#define P_SK_FLAG(n) \
690 if (flags & SOCK_##n) { \
691 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
692 flags &= ~SOCK_##n; \
693 }
694
695 P_SK_FLAG(CLOEXEC);
696 P_SK_FLAG(NONBLOCK);
697#undef P_SK_FLAG
698
699 if (flags)
700 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
701
702 return printed;
703}
704
705#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
706
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300707#ifndef MSG_PROBE
708#define MSG_PROBE 0x10
709#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600710#ifndef MSG_WAITFORONE
711#define MSG_WAITFORONE 0x10000
712#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300713#ifndef MSG_SENDPAGE_NOTLAST
714#define MSG_SENDPAGE_NOTLAST 0x20000
715#endif
716#ifndef MSG_FASTOPEN
717#define MSG_FASTOPEN 0x20000000
718#endif
719
720static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
721 struct syscall_arg *arg)
722{
723 int printed = 0, flags = arg->val;
724
725 if (flags == 0)
726 return scnprintf(bf, size, "NONE");
727#define P_MSG_FLAG(n) \
728 if (flags & MSG_##n) { \
729 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
730 flags &= ~MSG_##n; \
731 }
732
733 P_MSG_FLAG(OOB);
734 P_MSG_FLAG(PEEK);
735 P_MSG_FLAG(DONTROUTE);
736 P_MSG_FLAG(TRYHARD);
737 P_MSG_FLAG(CTRUNC);
738 P_MSG_FLAG(PROBE);
739 P_MSG_FLAG(TRUNC);
740 P_MSG_FLAG(DONTWAIT);
741 P_MSG_FLAG(EOR);
742 P_MSG_FLAG(WAITALL);
743 P_MSG_FLAG(FIN);
744 P_MSG_FLAG(SYN);
745 P_MSG_FLAG(CONFIRM);
746 P_MSG_FLAG(RST);
747 P_MSG_FLAG(ERRQUEUE);
748 P_MSG_FLAG(NOSIGNAL);
749 P_MSG_FLAG(MORE);
750 P_MSG_FLAG(WAITFORONE);
751 P_MSG_FLAG(SENDPAGE_NOTLAST);
752 P_MSG_FLAG(FASTOPEN);
753 P_MSG_FLAG(CMSG_CLOEXEC);
754#undef P_MSG_FLAG
755
756 if (flags)
757 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
758
759 return printed;
760}
761
762#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
763
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300764static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
765 struct syscall_arg *arg)
766{
767 size_t printed = 0;
768 int mode = arg->val;
769
770 if (mode == F_OK) /* 0 */
771 return scnprintf(bf, size, "F");
772#define P_MODE(n) \
773 if (mode & n##_OK) { \
774 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
775 mode &= ~n##_OK; \
776 }
777
778 P_MODE(R);
779 P_MODE(W);
780 P_MODE(X);
781#undef P_MODE
782
783 if (mode)
784 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
785
786 return printed;
787}
788
789#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
790
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300791static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
792 struct syscall_arg *arg);
793
794#define SCA_FILENAME syscall_arg__scnprintf_filename
795
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300796static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300797 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300798{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300799 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300800
801 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300802 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300803
804 if (flags == 0)
805 return scnprintf(bf, size, "RDONLY");
806#define P_FLAG(n) \
807 if (flags & O_##n) { \
808 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
809 flags &= ~O_##n; \
810 }
811
812 P_FLAG(APPEND);
813 P_FLAG(ASYNC);
814 P_FLAG(CLOEXEC);
815 P_FLAG(CREAT);
816 P_FLAG(DIRECT);
817 P_FLAG(DIRECTORY);
818 P_FLAG(EXCL);
819 P_FLAG(LARGEFILE);
820 P_FLAG(NOATIME);
821 P_FLAG(NOCTTY);
822#ifdef O_NONBLOCK
823 P_FLAG(NONBLOCK);
824#elif O_NDELAY
825 P_FLAG(NDELAY);
826#endif
827#ifdef O_PATH
828 P_FLAG(PATH);
829#endif
830 P_FLAG(RDWR);
831#ifdef O_DSYNC
832 if ((flags & O_SYNC) == O_SYNC)
833 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
834 else {
835 P_FLAG(DSYNC);
836 }
837#else
838 P_FLAG(SYNC);
839#endif
840 P_FLAG(TRUNC);
841 P_FLAG(WRONLY);
842#undef P_FLAG
843
844 if (flags)
845 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
846
847 return printed;
848}
849
850#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
851
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300852static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size,
853 struct syscall_arg *arg)
854{
855 int printed = 0, flags = arg->val;
856
857 if (flags == 0)
858 return 0;
859
860#define P_FLAG(n) \
861 if (flags & PERF_FLAG_##n) { \
862 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
863 flags &= ~PERF_FLAG_##n; \
864 }
865
866 P_FLAG(FD_NO_GROUP);
867 P_FLAG(FD_OUTPUT);
868 P_FLAG(PID_CGROUP);
869 P_FLAG(FD_CLOEXEC);
870#undef P_FLAG
871
872 if (flags)
873 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
874
875 return printed;
876}
877
878#define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags
879
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300880static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
881 struct syscall_arg *arg)
882{
883 int printed = 0, flags = arg->val;
884
885 if (flags == 0)
886 return scnprintf(bf, size, "NONE");
887#define P_FLAG(n) \
888 if (flags & EFD_##n) { \
889 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
890 flags &= ~EFD_##n; \
891 }
892
893 P_FLAG(SEMAPHORE);
894 P_FLAG(CLOEXEC);
895 P_FLAG(NONBLOCK);
896#undef P_FLAG
897
898 if (flags)
899 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
900
901 return printed;
902}
903
904#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
905
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300906static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
907 struct syscall_arg *arg)
908{
909 int printed = 0, flags = arg->val;
910
911#define P_FLAG(n) \
912 if (flags & O_##n) { \
913 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
914 flags &= ~O_##n; \
915 }
916
917 P_FLAG(CLOEXEC);
918 P_FLAG(NONBLOCK);
919#undef P_FLAG
920
921 if (flags)
922 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
923
924 return printed;
925}
926
927#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
928
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300929static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
930{
931 int sig = arg->val;
932
933 switch (sig) {
934#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
935 P_SIGNUM(HUP);
936 P_SIGNUM(INT);
937 P_SIGNUM(QUIT);
938 P_SIGNUM(ILL);
939 P_SIGNUM(TRAP);
940 P_SIGNUM(ABRT);
941 P_SIGNUM(BUS);
942 P_SIGNUM(FPE);
943 P_SIGNUM(KILL);
944 P_SIGNUM(USR1);
945 P_SIGNUM(SEGV);
946 P_SIGNUM(USR2);
947 P_SIGNUM(PIPE);
948 P_SIGNUM(ALRM);
949 P_SIGNUM(TERM);
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300950 P_SIGNUM(CHLD);
951 P_SIGNUM(CONT);
952 P_SIGNUM(STOP);
953 P_SIGNUM(TSTP);
954 P_SIGNUM(TTIN);
955 P_SIGNUM(TTOU);
956 P_SIGNUM(URG);
957 P_SIGNUM(XCPU);
958 P_SIGNUM(XFSZ);
959 P_SIGNUM(VTALRM);
960 P_SIGNUM(PROF);
961 P_SIGNUM(WINCH);
962 P_SIGNUM(IO);
963 P_SIGNUM(PWR);
964 P_SIGNUM(SYS);
Ben Hutchings02c5bb42014-02-06 01:00:41 +0000965#ifdef SIGEMT
966 P_SIGNUM(EMT);
967#endif
968#ifdef SIGSTKFLT
969 P_SIGNUM(STKFLT);
970#endif
971#ifdef SIGSWI
972 P_SIGNUM(SWI);
973#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300974 default: break;
975 }
976
977 return scnprintf(bf, size, "%#x", sig);
978}
979
980#define SCA_SIGNUM syscall_arg__scnprintf_signum
981
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300982#if defined(__i386__) || defined(__x86_64__)
983/*
984 * FIXME: Make this available to all arches.
985 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300986#define TCGETS 0x5401
987
988static const char *tioctls[] = {
989 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
990 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
991 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
992 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
993 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
994 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
995 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
996 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
997 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
998 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
999 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
1000 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
1001 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
1002 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
1003 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
1004};
1005
1006static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001007#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001008
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001009static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg)
1010{
1011 int op = arg->val;
1012 size_t printed = 0;
1013
1014 switch (op) {
1015#define P_SECCOMP_SET_MODE_OP(n) case SECCOMP_SET_MODE_##n: printed = scnprintf(bf, size, #n); break
1016 P_SECCOMP_SET_MODE_OP(STRICT);
1017 P_SECCOMP_SET_MODE_OP(FILTER);
1018#undef P_SECCOMP_SET_MODE_OP
1019 default: printed = scnprintf(bf, size, "%#x", op); break;
1020 }
1021
1022 return printed;
1023}
1024
1025#define SCA_SECCOMP_OP syscall_arg__scnprintf_seccomp_op
1026
1027static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size,
1028 struct syscall_arg *arg)
1029{
1030 int printed = 0, flags = arg->val;
1031
1032#define P_FLAG(n) \
1033 if (flags & SECCOMP_FILTER_FLAG_##n) { \
1034 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
1035 flags &= ~SECCOMP_FILTER_FLAG_##n; \
1036 }
1037
1038 P_FLAG(TSYNC);
1039#undef P_FLAG
1040
1041 if (flags)
1042 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
1043
1044 return printed;
1045}
1046
1047#define SCA_SECCOMP_FLAGS syscall_arg__scnprintf_seccomp_flags
1048
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -03001049static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
1050 struct syscall_arg *arg)
1051{
1052 int printed = 0, flags = arg->val;
1053
1054#define P_FLAG(n) \
1055 if (flags & GRND_##n) { \
1056 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
1057 flags &= ~GRND_##n; \
1058 }
1059
1060 P_FLAG(RANDOM);
1061 P_FLAG(NONBLOCK);
1062#undef P_FLAG
1063
1064 if (flags)
1065 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
1066
1067 return printed;
1068}
1069
1070#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
1071
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001072#define STRARRAY(arg, name, array) \
1073 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
1074 .arg_parm = { [arg] = &strarray__##array, }
1075
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001076#include "trace/beauty/sched_policy.c"
1077
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001078static struct syscall_fmt {
1079 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001080 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001081 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001082 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001083 bool errmsg;
1084 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001085 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001086} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -03001087 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001088 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1089 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001090 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -03001091 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001092 { .name = "brk", .hexret = true,
1093 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001094 { .name = "chdir", .errmsg = true,
1095 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1096 { .name = "chmod", .errmsg = true,
1097 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1098 { .name = "chroot", .errmsg = true,
1099 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -06001100 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001101 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001102 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -03001103 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001104 { .name = "creat", .errmsg = true,
1105 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001106 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001107 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001108 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001109 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001110 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001111 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001112 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -03001113 { .name = "eventfd2", .errmsg = true,
1114 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001115 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001116 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1117 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001118 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001119 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001120 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001121 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001122 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001123 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001124 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001125 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001126 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001127 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1128 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001129 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001130 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001131 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001132 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1133 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001134 { .name = "fcntl", .errmsg = true,
1135 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1136 [1] = SCA_STRARRAY, /* cmd */ },
1137 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1138 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001139 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -03001140 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001141 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1142 [1] = SCA_FLOCK, /* cmd */ }, },
1143 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001144 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001145 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001146 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001147 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001148 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1149 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001150 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001151 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001152 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001153 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001154 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001155 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -03001156 { .name = "futex", .errmsg = true,
1157 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001158 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001159 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1160 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001161 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001162 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001163 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001164 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001165 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -03001166 { .name = "getrandom", .errmsg = true,
1167 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001168 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001169 { .name = "getxattr", .errmsg = true,
1170 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1171 { .name = "inotify_add_watch", .errmsg = true,
1172 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001173 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001174 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001175#if defined(__i386__) || defined(__x86_64__)
1176/*
1177 * FIXME: Make this available to all arches.
1178 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001179 [1] = SCA_STRHEXARRAY, /* cmd */
1180 [2] = SCA_HEX, /* arg */ },
1181 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001182#else
1183 [2] = SCA_HEX, /* arg */ }, },
1184#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -03001185 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001186 { .name = "kill", .errmsg = true,
1187 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001188 { .name = "lchown", .errmsg = true,
1189 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1190 { .name = "lgetxattr", .errmsg = true,
1191 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001192 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001193 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001194 { .name = "listxattr", .errmsg = true,
1195 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001196 { .name = "llistxattr", .errmsg = true,
1197 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1198 { .name = "lremovexattr", .errmsg = true,
1199 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001200 { .name = "lseek", .errmsg = true,
1201 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1202 [2] = SCA_STRARRAY, /* whence */ },
1203 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001204 { .name = "lsetxattr", .errmsg = true,
1205 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001206 { .name = "lstat", .errmsg = true, .alias = "newlstat",
1207 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001208 { .name = "lsxattr", .errmsg = true,
1209 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001210 { .name = "madvise", .errmsg = true,
1211 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1212 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001213 { .name = "mkdir", .errmsg = true,
1214 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001215 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001216 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1217 [1] = SCA_FILENAME, /* pathname */ }, },
1218 { .name = "mknod", .errmsg = true,
1219 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001220 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001221 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1222 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001223 { .name = "mlock", .errmsg = true,
1224 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1225 { .name = "mlockall", .errmsg = true,
1226 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001227 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001228 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001229 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001230 [3] = SCA_MMAP_FLAGS, /* flags */
1231 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001232 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001233 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1234 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001235 { .name = "mq_unlink", .errmsg = true,
1236 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001237 { .name = "mremap", .hexret = true,
1238 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001239 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001240 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001241 { .name = "munlock", .errmsg = true,
1242 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001243 { .name = "munmap", .errmsg = true,
1244 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001245 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001246 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001247 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001248 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1249 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001250 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001251 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1252 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001253 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001254 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1255 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001256 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001257 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001258 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001259 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001260 { .name = "perf_event_open", .errmsg = true,
1261 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1262 [2] = SCA_INT, /* cpu */
1263 [3] = SCA_FD, /* group_fd */
1264 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001265 { .name = "pipe2", .errmsg = true,
1266 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001267 { .name = "poll", .errmsg = true, .timeout = true, },
1268 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001269 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001270 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001271 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001272 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001273 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001274 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001275 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001276 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001277 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001278 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001279 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001280 { .name = "readlink", .errmsg = true,
1281 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001282 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001283 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1284 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001285 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001286 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001287 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001288 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1289 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001290 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001291 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1292 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001293 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001294 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1295 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001296 { .name = "removexattr", .errmsg = true,
1297 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001298 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001299 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001300 { .name = "rmdir", .errmsg = true,
1301 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001302 { .name = "rt_sigaction", .errmsg = true,
1303 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001304 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001305 { .name = "rt_sigqueueinfo", .errmsg = true,
1306 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1307 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1308 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001309 { .name = "sched_setscheduler", .errmsg = true,
1310 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001311 { .name = "seccomp", .errmsg = true,
1312 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
1313 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001314 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001315 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001316 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1317 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001318 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001319 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1320 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001321 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001322 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1323 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001324 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1325 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001326 { .name = "setxattr", .errmsg = true,
1327 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001328 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001329 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001330 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001331 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1332 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001333 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001334 { .name = "socketpair", .errmsg = true,
1335 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1336 [1] = SCA_SK_TYPE, /* type */ },
1337 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001338 { .name = "stat", .errmsg = true, .alias = "newstat",
1339 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001340 { .name = "statfs", .errmsg = true,
1341 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1342 { .name = "swapoff", .errmsg = true,
1343 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1344 { .name = "swapon", .errmsg = true,
1345 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001346 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001347 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001348 { .name = "tgkill", .errmsg = true,
1349 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1350 { .name = "tkill", .errmsg = true,
1351 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001352 { .name = "truncate", .errmsg = true,
1353 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001354 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001355 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001356 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1357 [1] = SCA_FILENAME, /* pathname */ }, },
1358 { .name = "utime", .errmsg = true,
1359 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001360 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001361 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1362 [1] = SCA_FILENAME, /* filename */ }, },
1363 { .name = "utimes", .errmsg = true,
1364 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001365 { .name = "vmsplice", .errmsg = true,
1366 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001367 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001368 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001369 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001370 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001371};
1372
1373static int syscall_fmt__cmp(const void *name, const void *fmtp)
1374{
1375 const struct syscall_fmt *fmt = fmtp;
1376 return strcmp(name, fmt->name);
1377}
1378
1379static struct syscall_fmt *syscall_fmt__find(const char *name)
1380{
1381 const int nmemb = ARRAY_SIZE(syscall_fmts);
1382 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1383}
1384
1385struct syscall {
1386 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001387 int nr_args;
1388 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001389 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001390 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001391 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001392 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001393 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001394};
1395
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001396static size_t fprintf_duration(unsigned long t, FILE *fp)
1397{
1398 double duration = (double)t / NSEC_PER_MSEC;
1399 size_t printed = fprintf(fp, "(");
1400
1401 if (duration >= 1.0)
1402 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1403 else if (duration >= 0.01)
1404 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1405 else
1406 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001407 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001408}
1409
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001410/**
1411 * filename.ptr: The filename char pointer that will be vfs_getname'd
1412 * filename.entry_str_pos: Where to insert the string translated from
1413 * filename.ptr by the vfs_getname tracepoint/kprobe.
1414 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001415struct thread_trace {
1416 u64 entry_time;
1417 u64 exit_time;
1418 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001419 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001420 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001421 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001422 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001423 struct {
1424 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001425 short int entry_str_pos;
1426 bool pending_open;
1427 unsigned int namelen;
1428 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001429 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001430 struct {
1431 int max;
1432 char **table;
1433 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001434
1435 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001436};
1437
1438static struct thread_trace *thread_trace__new(void)
1439{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001440 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1441
1442 if (ttrace)
1443 ttrace->paths.max = -1;
1444
David Ahernbf2575c2013-10-08 21:26:53 -06001445 ttrace->syscall_stats = intlist__new(NULL);
1446
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001447 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001448}
1449
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001450static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001451{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001452 struct thread_trace *ttrace;
1453
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001454 if (thread == NULL)
1455 goto fail;
1456
Namhyung Kim89dceb22014-10-06 09:46:03 +09001457 if (thread__priv(thread) == NULL)
1458 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001459
Namhyung Kim89dceb22014-10-06 09:46:03 +09001460 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001461 goto fail;
1462
Namhyung Kim89dceb22014-10-06 09:46:03 +09001463 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001464 ++ttrace->nr_events;
1465
1466 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001467fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001468 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001469 "WARNING: not enough memory, dropping samples!\n");
1470 return NULL;
1471}
1472
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001473#define TRACE_PFMAJ (1 << 0)
1474#define TRACE_PFMIN (1 << 1)
1475
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001476static const size_t trace__entry_str_size = 2048;
1477
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001478struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001479 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001480 struct {
1481 int machine;
1482 int open_id;
1483 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001484 struct {
1485 int max;
1486 struct syscall *table;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001487 struct {
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001488 struct perf_evsel *sys_enter,
1489 *sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001490 } events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001491 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001492 struct record_opts opts;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001493 struct perf_evlist *evlist;
David Ahern8fb598e2013-09-28 13:13:00 -06001494 struct machine *host;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001495 struct thread *current;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001496 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001497 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001498 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001499 struct strlist *ev_qualifier;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001500 struct {
1501 size_t nr;
1502 int *entries;
1503 } ev_qualifier_ids;
David Ahernbdc89662013-08-28 22:29:53 -06001504 struct intlist *tid_list;
1505 struct intlist *pid_list;
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08001506 struct {
1507 size_t nr;
1508 pid_t *entries;
1509 } filter_pids;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001510 double duration_filter;
1511 double runtime_ms;
1512 struct {
1513 u64 vfs_getname,
1514 proc_getname;
1515 } stats;
1516 bool not_ev_qualifier;
1517 bool live;
1518 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001519 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001520 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001521 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001522 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001523 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001524 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001525 bool trace_syscalls;
Yunlong Songe366a6d2015-04-02 21:47:18 +08001526 bool force;
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03001527 bool vfs_getname;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001528 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001529};
1530
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001531static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001532{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001533 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001534
1535 if (fd > ttrace->paths.max) {
1536 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1537
1538 if (npath == NULL)
1539 return -1;
1540
1541 if (ttrace->paths.max != -1) {
1542 memset(npath + ttrace->paths.max + 1, 0,
1543 (fd - ttrace->paths.max) * sizeof(char *));
1544 } else {
1545 memset(npath, 0, (fd + 1) * sizeof(char *));
1546 }
1547
1548 ttrace->paths.table = npath;
1549 ttrace->paths.max = fd;
1550 }
1551
1552 ttrace->paths.table[fd] = strdup(pathname);
1553
1554 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1555}
1556
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001557static int thread__read_fd_path(struct thread *thread, int fd)
1558{
1559 char linkname[PATH_MAX], pathname[PATH_MAX];
1560 struct stat st;
1561 int ret;
1562
1563 if (thread->pid_ == thread->tid) {
1564 scnprintf(linkname, sizeof(linkname),
1565 "/proc/%d/fd/%d", thread->pid_, fd);
1566 } else {
1567 scnprintf(linkname, sizeof(linkname),
1568 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1569 }
1570
1571 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1572 return -1;
1573
1574 ret = readlink(linkname, pathname, sizeof(pathname));
1575
1576 if (ret < 0 || ret > st.st_size)
1577 return -1;
1578
1579 pathname[ret] = '\0';
1580 return trace__set_fd_pathname(thread, fd, pathname);
1581}
1582
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001583static const char *thread__fd_path(struct thread *thread, int fd,
1584 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001585{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001586 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001587
1588 if (ttrace == NULL)
1589 return NULL;
1590
1591 if (fd < 0)
1592 return NULL;
1593
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001594 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001595 if (!trace->live)
1596 return NULL;
1597 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001598 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001599 return NULL;
1600 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001601
1602 return ttrace->paths.table[fd];
1603}
1604
1605static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1606 struct syscall_arg *arg)
1607{
1608 int fd = arg->val;
1609 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001610 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001611
1612 if (path)
1613 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1614
1615 return printed;
1616}
1617
1618static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1619 struct syscall_arg *arg)
1620{
1621 int fd = arg->val;
1622 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001623 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001624
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001625 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1626 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001627
1628 return printed;
1629}
1630
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001631static void thread__set_filename_pos(struct thread *thread, const char *bf,
1632 unsigned long ptr)
1633{
1634 struct thread_trace *ttrace = thread__priv(thread);
1635
1636 ttrace->filename.ptr = ptr;
1637 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1638}
1639
1640static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1641 struct syscall_arg *arg)
1642{
1643 unsigned long ptr = arg->val;
1644
1645 if (!arg->trace->vfs_getname)
1646 return scnprintf(bf, size, "%#x", ptr);
1647
1648 thread__set_filename_pos(arg->thread, bf, ptr);
1649 return 0;
1650}
1651
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001652static bool trace__filter_duration(struct trace *trace, double t)
1653{
1654 return t < (trace->duration_filter * NSEC_PER_MSEC);
1655}
1656
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001657static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1658{
1659 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1660
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001661 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001662}
1663
Namhyung Kimf15eb532012-10-05 14:02:16 +09001664static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001665static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001666
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001667static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001668{
1669 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001670 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001671}
1672
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001673static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001674 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001675{
1676 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001677 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001678
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001679 if (trace->multiple_threads) {
1680 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001681 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001682 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001683 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001684
1685 return printed;
1686}
1687
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001688static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001689 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001690{
1691 int ret = 0;
1692
1693 switch (event->header.type) {
1694 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001695 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001696 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001697 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001698 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001699 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001700 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001701 break;
1702 }
1703
1704 return ret;
1705}
1706
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001707static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001708 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001709 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001710 struct machine *machine)
1711{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001712 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001713 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001714}
1715
1716static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1717{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001718 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001719
1720 if (err)
1721 return err;
1722
David Ahern8fb598e2013-09-28 13:13:00 -06001723 trace->host = machine__new_host();
1724 if (trace->host == NULL)
1725 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001726
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001727 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001728 return -errno;
1729
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001730 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001731 evlist->threads, trace__tool_process, false,
1732 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001733 if (err)
1734 symbol__exit();
1735
1736 return err;
1737}
1738
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001739static int syscall__set_arg_fmts(struct syscall *sc)
1740{
1741 struct format_field *field;
1742 int idx = 0;
1743
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001744 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001745 if (sc->arg_scnprintf == NULL)
1746 return -1;
1747
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001748 if (sc->fmt)
1749 sc->arg_parm = sc->fmt->arg_parm;
1750
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001751 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001752 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1753 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1754 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001755 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1756 ++idx;
1757 }
1758
1759 return 0;
1760}
1761
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001762static int trace__read_syscall_info(struct trace *trace, int id)
1763{
1764 char tp_name[128];
1765 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001766 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001767
1768 if (name == NULL)
1769 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001770
1771 if (id > trace->syscalls.max) {
1772 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1773
1774 if (nsyscalls == NULL)
1775 return -1;
1776
1777 if (trace->syscalls.max != -1) {
1778 memset(nsyscalls + trace->syscalls.max + 1, 0,
1779 (id - trace->syscalls.max) * sizeof(*sc));
1780 } else {
1781 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1782 }
1783
1784 trace->syscalls.table = nsyscalls;
1785 trace->syscalls.max = id;
1786 }
1787
1788 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001789 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001790
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001791 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001792
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001793 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001794 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001795
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001796 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001797 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001798 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001799 }
1800
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001801 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001802 return -1;
1803
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001804 sc->args = sc->tp_format->format.fields;
1805 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001806 /*
1807 * We need to check and discard the first variable '__syscall_nr'
1808 * or 'nr' that mean the syscall number. It is needless here.
1809 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1810 */
1811 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001812 sc->args = sc->args->next;
1813 --sc->nr_args;
1814 }
1815
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001816 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1817
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001818 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001819}
1820
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001821static int trace__validate_ev_qualifier(struct trace *trace)
1822{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001823 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001824 struct str_node *pos;
1825
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001826 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1827 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1828 sizeof(trace->ev_qualifier_ids.entries[0]));
1829
1830 if (trace->ev_qualifier_ids.entries == NULL) {
1831 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1832 trace->output);
1833 err = -EINVAL;
1834 goto out;
1835 }
1836
1837 i = 0;
1838
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001839 strlist__for_each(pos, trace->ev_qualifier) {
1840 const char *sc = pos->s;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001841 int id = audit_name_to_syscall(sc, trace->audit.machine);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001842
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001843 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001844 if (err == 0) {
1845 fputs("Error:\tInvalid syscall ", trace->output);
1846 err = -EINVAL;
1847 } else {
1848 fputs(", ", trace->output);
1849 }
1850
1851 fputs(sc, trace->output);
1852 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001853
1854 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001855 }
1856
1857 if (err < 0) {
1858 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1859 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001860 zfree(&trace->ev_qualifier_ids.entries);
1861 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001862 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001863out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001864 return err;
1865}
1866
David Ahern55d43bca2015-02-19 15:00:22 -05001867/*
1868 * args is to be interpreted as a series of longs but we need to handle
1869 * 8-byte unaligned accesses. args points to raw_data within the event
1870 * and raw_data is guaranteed to be 8-byte unaligned because it is
1871 * preceded by raw_size which is a u32. So we need to copy args to a temp
1872 * variable to read it. Most notably this avoids extended load instructions
1873 * on unaligned addresses
1874 */
1875
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001876static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001877 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001878 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001879{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001880 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001881 unsigned char *p;
1882 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001883
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001884 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001885 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001886 u8 bit = 1;
1887 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001888 .idx = 0,
1889 .mask = 0,
1890 .trace = trace,
1891 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001892 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001893
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001894 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001895 field = field->next, ++arg.idx, bit <<= 1) {
1896 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001897 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001898
1899 /* special care for unaligned accesses */
1900 p = args + sizeof(unsigned long) * arg.idx;
1901 memcpy(&val, p, sizeof(val));
1902
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001903 /*
1904 * Suppress this argument if its value is zero and
1905 * and we don't have a string associated in an
1906 * strarray for it.
1907 */
David Ahern55d43bca2015-02-19 15:00:22 -05001908 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001909 !(sc->arg_scnprintf &&
1910 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1911 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001912 continue;
1913
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001914 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001915 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001916 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bca2015-02-19 15:00:22 -05001917 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001918 if (sc->arg_parm)
1919 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001920 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1921 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001922 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001923 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bca2015-02-19 15:00:22 -05001924 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001925 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001926 }
1927 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001928 int i = 0;
1929
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001930 while (i < 6) {
David Ahern55d43bca2015-02-19 15:00:22 -05001931 /* special care for unaligned accesses */
1932 p = args + sizeof(unsigned long) * i;
1933 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001934 printed += scnprintf(bf + printed, size - printed,
1935 "%sarg%d: %ld",
David Ahern55d43bca2015-02-19 15:00:22 -05001936 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001937 ++i;
1938 }
1939 }
1940
1941 return printed;
1942}
1943
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001944typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001945 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001946 struct perf_sample *sample);
1947
1948static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001949 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001950{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001951
1952 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001953
1954 /*
1955 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1956 * before that, leaving at a higher verbosity level till that is
1957 * explained. Reproduced with plain ftrace with:
1958 *
1959 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1960 * grep "NR -1 " /t/trace_pipe
1961 *
1962 * After generating some load on the machine.
1963 */
1964 if (verbose > 1) {
1965 static u64 n;
1966 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1967 id, perf_evsel__name(evsel), ++n);
1968 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001969 return NULL;
1970 }
1971
1972 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1973 trace__read_syscall_info(trace, id))
1974 goto out_cant_read;
1975
1976 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1977 goto out_cant_read;
1978
1979 return &trace->syscalls.table[id];
1980
1981out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001982 if (verbose) {
1983 fprintf(trace->output, "Problems reading syscall %d", id);
1984 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1985 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1986 fputs(" information\n", trace->output);
1987 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001988 return NULL;
1989}
1990
David Ahernbf2575c2013-10-08 21:26:53 -06001991static void thread__update_stats(struct thread_trace *ttrace,
1992 int id, struct perf_sample *sample)
1993{
1994 struct int_node *inode;
1995 struct stats *stats;
1996 u64 duration = 0;
1997
1998 inode = intlist__findnew(ttrace->syscall_stats, id);
1999 if (inode == NULL)
2000 return;
2001
2002 stats = inode->priv;
2003 if (stats == NULL) {
2004 stats = malloc(sizeof(struct stats));
2005 if (stats == NULL)
2006 return;
2007 init_stats(stats);
2008 inode->priv = stats;
2009 }
2010
2011 if (ttrace->entry_time && sample->time > ttrace->entry_time)
2012 duration = sample->time - ttrace->entry_time;
2013
2014 update_stats(stats, duration);
2015}
2016
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03002017static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
2018{
2019 struct thread_trace *ttrace;
2020 u64 duration;
2021 size_t printed;
2022
2023 if (trace->current == NULL)
2024 return 0;
2025
2026 ttrace = thread__priv(trace->current);
2027
2028 if (!ttrace->entry_pending)
2029 return 0;
2030
2031 duration = sample->time - ttrace->entry_time;
2032
2033 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
2034 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
2035 ttrace->entry_pending = false;
2036
2037 return printed;
2038}
2039
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002040static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002041 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002042 struct perf_sample *sample)
2043{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002044 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002045 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002046 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002047 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002048 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002049 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002050 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002051
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002052 if (sc == NULL)
2053 return -1;
2054
David Ahern8fb598e2013-09-28 13:13:00 -06002055 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002056 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002057 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002058 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002059
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002060 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002061
2062 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002063 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002064 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002065 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002066 }
2067
David Ahern13f22a22015-03-19 12:23:03 -06002068 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03002069 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03002070
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002071 ttrace->entry_time = sample->time;
2072 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002073 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002074
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002075 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002076 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002077
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03002078 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07002079 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002080 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
2081 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002082 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002083 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002084 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002085 /* See trace__vfs_getname & trace__sys_exit */
2086 ttrace->filename.pending_open = false;
2087 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002088
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002089 if (trace->current != thread) {
2090 thread__put(trace->current);
2091 trace->current = thread__get(thread);
2092 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002093 err = 0;
2094out_put:
2095 thread__put(thread);
2096 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002097}
2098
2099static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002100 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002101 struct perf_sample *sample)
2102{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002103 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002104 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002105 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002106 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002107 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002108 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002109
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002110 if (sc == NULL)
2111 return -1;
2112
David Ahern8fb598e2013-09-28 13:13:00 -06002113 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002114 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002115 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002116 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002117
David Ahernbf2575c2013-10-08 21:26:53 -06002118 if (trace->summary)
2119 thread__update_stats(ttrace, id, sample);
2120
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002121 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002122
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002123 if (id == trace->audit.open_id && ret >= 0 && ttrace->filename.pending_open) {
2124 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
2125 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002126 ++trace->stats.vfs_getname;
2127 }
2128
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002129 ttrace->exit_time = sample->time;
2130
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002131 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002132 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002133 if (trace__filter_duration(trace, duration))
2134 goto out;
2135 } else if (trace->duration_filter)
2136 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002137
David Ahernfd2eaba2013-11-12 09:31:15 -07002138 if (trace->summary_only)
2139 goto out;
2140
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002141 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002142
2143 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002144 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002145 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002146 fprintf(trace->output, " ... [");
2147 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
2148 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002149 }
2150
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002151 if (sc->fmt == NULL) {
2152signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002153 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002154 } else if (ret < 0 && sc->fmt->errmsg) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00002155 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002156 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
2157 *e = audit_errno_to_name(-ret);
2158
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002159 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002160 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002161 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03002162 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002163 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002164 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002165 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002166
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002167 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002168out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002169 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002170 err = 0;
2171out_put:
2172 thread__put(thread);
2173 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002174}
2175
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002176static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002177 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002178 struct perf_sample *sample)
2179{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002180 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2181 struct thread_trace *ttrace;
2182 size_t filename_len, entry_str_len, to_move;
2183 ssize_t remaining_space;
2184 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002185 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002186
2187 if (!thread)
2188 goto out;
2189
2190 ttrace = thread__priv(thread);
2191 if (!ttrace)
2192 goto out;
2193
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002194 filename_len = strlen(filename);
2195
2196 if (ttrace->filename.namelen < filename_len) {
2197 char *f = realloc(ttrace->filename.name, filename_len + 1);
2198
2199 if (f == NULL)
2200 goto out;
2201
2202 ttrace->filename.namelen = filename_len;
2203 ttrace->filename.name = f;
2204 }
2205
2206 strcpy(ttrace->filename.name, filename);
2207 ttrace->filename.pending_open = true;
2208
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002209 if (!ttrace->filename.ptr)
2210 goto out;
2211
2212 entry_str_len = strlen(ttrace->entry_str);
2213 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2214 if (remaining_space <= 0)
2215 goto out;
2216
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002217 if (filename_len > (size_t)remaining_space) {
2218 filename += filename_len - remaining_space;
2219 filename_len = remaining_space;
2220 }
2221
2222 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2223 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2224 memmove(pos + filename_len, pos, to_move);
2225 memcpy(pos, filename, filename_len);
2226
2227 ttrace->filename.ptr = 0;
2228 ttrace->filename.entry_str_pos = 0;
2229out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002230 return 0;
2231}
2232
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002233static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002234 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002235 struct perf_sample *sample)
2236{
2237 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2238 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06002239 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03002240 sample->pid,
2241 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002242 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002243
2244 if (ttrace == NULL)
2245 goto out_dump;
2246
2247 ttrace->runtime_ms += runtime_ms;
2248 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002249 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002250 return 0;
2251
2252out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002253 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002254 evsel->name,
2255 perf_evsel__strval(evsel, sample, "comm"),
2256 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2257 runtime,
2258 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002259 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002260 return 0;
2261}
2262
Wang Nan1d6c9402016-02-26 09:31:55 +00002263static void bpf_output__printer(enum binary_printer_ops op,
2264 unsigned int val, void *extra)
2265{
2266 FILE *output = extra;
2267 unsigned char ch = (unsigned char)val;
2268
2269 switch (op) {
2270 case BINARY_PRINT_CHAR_DATA:
2271 fprintf(output, "%c", isprint(ch) ? ch : '.');
2272 break;
2273 case BINARY_PRINT_DATA_BEGIN:
2274 case BINARY_PRINT_LINE_BEGIN:
2275 case BINARY_PRINT_ADDR:
2276 case BINARY_PRINT_NUM_DATA:
2277 case BINARY_PRINT_NUM_PAD:
2278 case BINARY_PRINT_SEP:
2279 case BINARY_PRINT_CHAR_PAD:
2280 case BINARY_PRINT_LINE_END:
2281 case BINARY_PRINT_DATA_END:
2282 default:
2283 break;
2284 }
2285}
2286
2287static void bpf_output__fprintf(struct trace *trace,
2288 struct perf_sample *sample)
2289{
2290 print_binary(sample->raw_data, sample->raw_size, 8,
2291 bpf_output__printer, trace->output);
2292}
2293
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002294static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2295 union perf_event *event __maybe_unused,
2296 struct perf_sample *sample)
2297{
2298 trace__printf_interrupted_entry(trace, sample);
2299 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002300
2301 if (trace->trace_syscalls)
2302 fprintf(trace->output, "( ): ");
2303
2304 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002305
Wang Nan1d6c9402016-02-26 09:31:55 +00002306 if (perf_evsel__is_bpf_output(evsel)) {
2307 bpf_output__fprintf(trace, sample);
2308 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002309 event_format__fprintf(evsel->tp_format, sample->cpu,
2310 sample->raw_data, sample->raw_size,
2311 trace->output);
2312 }
2313
2314 fprintf(trace->output, ")\n");
2315 return 0;
2316}
2317
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002318static void print_location(FILE *f, struct perf_sample *sample,
2319 struct addr_location *al,
2320 bool print_dso, bool print_sym)
2321{
2322
2323 if ((verbose || print_dso) && al->map)
2324 fprintf(f, "%s@", al->map->dso->long_name);
2325
2326 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002327 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002328 al->addr - al->sym->start);
2329 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002330 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002331 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002332 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002333}
2334
2335static int trace__pgfault(struct trace *trace,
2336 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002337 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002338 struct perf_sample *sample)
2339{
2340 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002341 struct addr_location al;
2342 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002343 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002344 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002345
2346 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002347 ttrace = thread__trace(thread, trace->output);
2348 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002349 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002350
2351 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2352 ttrace->pfmaj++;
2353 else
2354 ttrace->pfmin++;
2355
2356 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002357 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002358
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002359 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002360 sample->ip, &al);
2361
2362 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2363
2364 fprintf(trace->output, "%sfault [",
2365 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2366 "maj" : "min");
2367
2368 print_location(trace->output, sample, &al, false, true);
2369
2370 fprintf(trace->output, "] => ");
2371
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002372 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002373 sample->addr, &al);
2374
2375 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002376 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002377 MAP__FUNCTION, sample->addr, &al);
2378
2379 if (al.map)
2380 map_type = 'x';
2381 else
2382 map_type = '?';
2383 }
2384
2385 print_location(trace->output, sample, &al, true, false);
2386
2387 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002388out:
2389 err = 0;
2390out_put:
2391 thread__put(thread);
2392 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002393}
2394
David Ahernbdc89662013-08-28 22:29:53 -06002395static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2396{
2397 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2398 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2399 return false;
2400
2401 if (trace->pid_list || trace->tid_list)
2402 return true;
2403
2404 return false;
2405}
2406
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002407static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002408 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002409 struct perf_sample *sample)
2410{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002411 /*
2412 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2413 * and don't use sample->time unconditionally, we may end up having
2414 * some other event in the future without PERF_SAMPLE_TIME for good
2415 * reason, i.e. we may not be interested in its timestamps, just in
2416 * it taking place, picking some piece of information when it
2417 * appears in our event stream (vfs_getname comes to mind).
2418 */
2419 if (trace->base_time == 0 && !trace->full_time &&
2420 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002421 trace->base_time = sample->time;
2422}
2423
David Ahern6810fc92013-08-28 22:29:52 -06002424static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002425 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002426 struct perf_sample *sample,
2427 struct perf_evsel *evsel,
2428 struct machine *machine __maybe_unused)
2429{
2430 struct trace *trace = container_of(tool, struct trace, tool);
2431 int err = 0;
2432
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002433 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002434
David Ahernbdc89662013-08-28 22:29:53 -06002435 if (skip_sample(trace, sample))
2436 return 0;
2437
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002438 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002439
David Ahern31605652013-12-04 19:41:41 -07002440 if (handler) {
2441 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002442 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002443 }
David Ahern6810fc92013-08-28 22:29:52 -06002444
2445 return err;
2446}
2447
David Ahernbdc89662013-08-28 22:29:53 -06002448static int parse_target_str(struct trace *trace)
2449{
2450 if (trace->opts.target.pid) {
2451 trace->pid_list = intlist__new(trace->opts.target.pid);
2452 if (trace->pid_list == NULL) {
2453 pr_err("Error parsing process id string\n");
2454 return -EINVAL;
2455 }
2456 }
2457
2458 if (trace->opts.target.tid) {
2459 trace->tid_list = intlist__new(trace->opts.target.tid);
2460 if (trace->tid_list == NULL) {
2461 pr_err("Error parsing thread id string\n");
2462 return -EINVAL;
2463 }
2464 }
2465
2466 return 0;
2467}
2468
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002469static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002470{
2471 unsigned int rec_argc, i, j;
2472 const char **rec_argv;
2473 const char * const record_args[] = {
2474 "record",
2475 "-R",
2476 "-m", "1024",
2477 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002478 };
2479
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002480 const char * const sc_args[] = { "-e", };
2481 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2482 const char * const majpf_args[] = { "-e", "major-faults" };
2483 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2484 const char * const minpf_args[] = { "-e", "minor-faults" };
2485 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2486
David Ahern9aca7f12013-12-04 19:41:39 -07002487 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002488 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2489 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002490 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2491
2492 if (rec_argv == NULL)
2493 return -ENOMEM;
2494
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002495 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002496 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002497 rec_argv[j++] = record_args[i];
2498
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002499 if (trace->trace_syscalls) {
2500 for (i = 0; i < sc_args_nr; i++)
2501 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002502
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002503 /* event string may be different for older kernels - e.g., RHEL6 */
2504 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2505 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2506 else if (is_valid_tracepoint("syscalls:sys_enter"))
2507 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2508 else {
2509 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2510 return -1;
2511 }
David Ahern9aca7f12013-12-04 19:41:39 -07002512 }
David Ahern9aca7f12013-12-04 19:41:39 -07002513
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002514 if (trace->trace_pgfaults & TRACE_PFMAJ)
2515 for (i = 0; i < majpf_args_nr; i++)
2516 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002517
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002518 if (trace->trace_pgfaults & TRACE_PFMIN)
2519 for (i = 0; i < minpf_args_nr; i++)
2520 rec_argv[j++] = minpf_args[i];
2521
2522 for (i = 0; i < (unsigned int)argc; i++)
2523 rec_argv[j++] = argv[i];
2524
2525 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002526}
2527
David Ahernbf2575c2013-10-08 21:26:53 -06002528static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2529
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002530static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002531{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002532 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002533
2534 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002535 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002536
2537 if (perf_evsel__field(evsel, "pathname") == NULL) {
2538 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002539 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002540 }
2541
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002542 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002543 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002544 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002545}
2546
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002547static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2548 u64 config)
2549{
2550 struct perf_evsel *evsel;
2551 struct perf_event_attr attr = {
2552 .type = PERF_TYPE_SOFTWARE,
2553 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002554 };
2555
2556 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002557 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002558
2559 event_attr_init(&attr);
2560
2561 evsel = perf_evsel__new(&attr);
2562 if (!evsel)
2563 return -ENOMEM;
2564
2565 evsel->handler = trace__pgfault;
2566 perf_evlist__add(evlist, evsel);
2567
2568 return 0;
2569}
2570
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002571static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2572{
2573 const u32 type = event->header.type;
2574 struct perf_evsel *evsel;
2575
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002576 if (type != PERF_RECORD_SAMPLE) {
2577 trace__process_event(trace, trace->host, event, sample);
2578 return;
2579 }
2580
2581 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2582 if (evsel == NULL) {
2583 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2584 return;
2585 }
2586
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002587 trace__set_base_time(trace, evsel, sample);
2588
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002589 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2590 sample->raw_data == NULL) {
2591 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2592 perf_evsel__name(evsel), sample->tid,
2593 sample->cpu, sample->raw_size);
2594 } else {
2595 tracepoint_handler handler = evsel->handler;
2596 handler(trace, evsel, event, sample);
2597 }
2598}
2599
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002600static int trace__add_syscall_newtp(struct trace *trace)
2601{
2602 int ret = -1;
2603 struct perf_evlist *evlist = trace->evlist;
2604 struct perf_evsel *sys_enter, *sys_exit;
2605
2606 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2607 if (sys_enter == NULL)
2608 goto out;
2609
2610 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2611 goto out_delete_sys_enter;
2612
2613 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2614 if (sys_exit == NULL)
2615 goto out_delete_sys_enter;
2616
2617 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2618 goto out_delete_sys_exit;
2619
2620 perf_evlist__add(evlist, sys_enter);
2621 perf_evlist__add(evlist, sys_exit);
2622
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002623 trace->syscalls.events.sys_enter = sys_enter;
2624 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002625
2626 ret = 0;
2627out:
2628 return ret;
2629
2630out_delete_sys_exit:
2631 perf_evsel__delete_priv(sys_exit);
2632out_delete_sys_enter:
2633 perf_evsel__delete_priv(sys_enter);
2634 goto out;
2635}
2636
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002637static int trace__set_ev_qualifier_filter(struct trace *trace)
2638{
2639 int err = -1;
2640 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2641 trace->ev_qualifier_ids.nr,
2642 trace->ev_qualifier_ids.entries);
2643
2644 if (filter == NULL)
2645 goto out_enomem;
2646
2647 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2648 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2649
2650 free(filter);
2651out:
2652 return err;
2653out_enomem:
2654 errno = ENOMEM;
2655 goto out;
2656}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002657
Namhyung Kimf15eb532012-10-05 14:02:16 +09002658static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002659{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002660 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002661 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002662 int err = -1, i;
2663 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002664 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002665 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002666
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002667 trace->live = true;
2668
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002669 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002670 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002671
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002672 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002673 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002674
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002675 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002676 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002677 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002678 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002679
2680 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2681 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002682 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002683
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002684 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002685 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2686 trace__sched_stat_runtime))
2687 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002688
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002689 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2690 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002691 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002692 goto out_delete_evlist;
2693 }
2694
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002695 err = trace__symbols_init(trace, evlist);
2696 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002697 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002698 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002699 }
2700
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002701 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002702
Namhyung Kimf15eb532012-10-05 14:02:16 +09002703 signal(SIGCHLD, sig_handler);
2704 signal(SIGINT, sig_handler);
2705
2706 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002707 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002708 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002709 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002710 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002711 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002712 }
2713 }
2714
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002715 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002716 if (err < 0)
2717 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002718
Wang Nanba504232016-02-26 09:31:54 +00002719 err = bpf__apply_obj_config();
2720 if (err) {
2721 char errbuf[BUFSIZ];
2722
2723 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2724 pr_err("ERROR: Apply config to BPF failed: %s\n",
2725 errbuf);
2726 goto out_error_open;
2727 }
2728
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002729 /*
2730 * Better not use !target__has_task() here because we need to cover the
2731 * case where no threads were specified in the command line, but a
2732 * workload was, and in that case we will fill in the thread_map when
2733 * we fork the workload in perf_evlist__prepare_workload.
2734 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002735 if (trace->filter_pids.nr > 0)
2736 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002737 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002738 err = perf_evlist__set_filter_pid(evlist, getpid());
2739
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002740 if (err < 0)
2741 goto out_error_mem;
2742
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002743 if (trace->ev_qualifier_ids.nr > 0) {
2744 err = trace__set_ev_qualifier_filter(trace);
2745 if (err < 0)
2746 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002747
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002748 pr_debug("event qualifier tracepoint filter: %s\n",
2749 trace->syscalls.events.sys_exit->filter);
2750 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002751
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002752 err = perf_evlist__apply_filters(evlist, &evsel);
2753 if (err < 0)
2754 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002755
Jiri Olsaf8850372013-11-28 17:57:22 +01002756 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002757 if (err < 0)
2758 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002759
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002760 if (!target__none(&trace->opts.target))
2761 perf_evlist__enable(evlist);
2762
Namhyung Kimf15eb532012-10-05 14:02:16 +09002763 if (forks)
2764 perf_evlist__start_workload(evlist);
2765
Jiri Olsae13798c2015-06-23 00:36:02 +02002766 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002767 evlist->threads->nr > 1 ||
2768 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002769again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002770 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002771
2772 for (i = 0; i < evlist->nr_mmaps; i++) {
2773 union perf_event *event;
2774
2775 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002776 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002777
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002778 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002779
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002780 err = perf_evlist__parse_sample(evlist, event, &sample);
2781 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002782 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002783 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002784 }
2785
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002786 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002787next_event:
2788 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002789
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002790 if (interrupted)
2791 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002792
2793 if (done && !draining) {
2794 perf_evlist__disable(evlist);
2795 draining = true;
2796 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002797 }
2798 }
2799
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002800 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002801 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002802
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002803 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2804 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2805 draining = true;
2806
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002807 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002808 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002809 } else {
2810 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002811 }
2812
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002813out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002814 thread__zput(trace->current);
2815
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002816 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002817
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002818 if (!err) {
2819 if (trace->summary)
2820 trace__fprintf_thread_summary(trace, trace->output);
2821
2822 if (trace->show_tool_stats) {
2823 fprintf(trace->output, "Stats:\n "
2824 " vfs_getname : %" PRIu64 "\n"
2825 " proc_getname: %" PRIu64 "\n",
2826 trace->stats.vfs_getname,
2827 trace->stats.proc_getname);
2828 }
2829 }
David Ahernbf2575c2013-10-08 21:26:53 -06002830
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002831out_delete_evlist:
2832 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002833 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002834 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002835 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002836{
2837 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002838
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002839out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002840 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002841 goto out_error;
2842
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002843out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002844 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002845 goto out_error;
2846
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002847out_error_mmap:
2848 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2849 goto out_error;
2850
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002851out_error_open:
2852 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2853
2854out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002855 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302856 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002857
2858out_error_apply_filters:
2859 fprintf(trace->output,
2860 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2861 evsel->filter, perf_evsel__name(evsel), errno,
2862 strerror_r(errno, errbuf, sizeof(errbuf)));
2863 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002864}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002865out_error_mem:
2866 fprintf(trace->output, "Not enough memory to run!\n");
2867 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002868
2869out_errno:
2870 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2871 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002872}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002873
David Ahern6810fc92013-08-28 22:29:52 -06002874static int trace__replay(struct trace *trace)
2875{
2876 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002877 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002878 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002879 struct perf_data_file file = {
2880 .path = input_name,
2881 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002882 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002883 };
David Ahern6810fc92013-08-28 22:29:52 -06002884 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002885 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002886 int err = -1;
2887
2888 trace->tool.sample = trace__process_sample;
2889 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002890 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002891 trace->tool.comm = perf_event__process_comm;
2892 trace->tool.exit = perf_event__process_exit;
2893 trace->tool.fork = perf_event__process_fork;
2894 trace->tool.attr = perf_event__process_attr;
2895 trace->tool.tracing_data = perf_event__process_tracing_data;
2896 trace->tool.build_id = perf_event__process_build_id;
2897
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002898 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002899 trace->tool.ordering_requires_timestamps = true;
2900
2901 /* add tid to output */
2902 trace->multiple_threads = true;
2903
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002904 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002905 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002906 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002907
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002908 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002909 goto out;
2910
David Ahern8fb598e2013-09-28 13:13:00 -06002911 trace->host = &session->machines.host;
2912
David Ahern6810fc92013-08-28 22:29:52 -06002913 err = perf_session__set_tracepoints_handlers(session, handlers);
2914 if (err)
2915 goto out;
2916
Namhyung Kim003824e2013-11-12 15:25:00 +09002917 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2918 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002919 /* older kernels have syscalls tp versus raw_syscalls */
2920 if (evsel == NULL)
2921 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2922 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002923
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002924 if (evsel &&
2925 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2926 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002927 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2928 goto out;
2929 }
2930
2931 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2932 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002933 if (evsel == NULL)
2934 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2935 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002936 if (evsel &&
2937 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2938 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002939 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002940 goto out;
2941 }
2942
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002943 evlist__for_each(session->evlist, evsel) {
2944 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2945 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2946 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2947 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2948 evsel->handler = trace__pgfault;
2949 }
2950
David Ahernbdc89662013-08-28 22:29:53 -06002951 err = parse_target_str(trace);
2952 if (err != 0)
2953 goto out;
2954
David Ahern6810fc92013-08-28 22:29:52 -06002955 setup_pager();
2956
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002957 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002958 if (err)
2959 pr_err("Failed to process events, error %d", err);
2960
David Ahernbf2575c2013-10-08 21:26:53 -06002961 else if (trace->summary)
2962 trace__fprintf_thread_summary(trace, trace->output);
2963
David Ahern6810fc92013-08-28 22:29:52 -06002964out:
2965 perf_session__delete(session);
2966
2967 return err;
2968}
2969
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002970static size_t trace__fprintf_threads_header(FILE *fp)
2971{
2972 size_t printed;
2973
Pekka Enberg99ff7152013-11-12 16:42:14 +02002974 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002975
2976 return printed;
2977}
2978
2979static size_t thread__dump_stats(struct thread_trace *ttrace,
2980 struct trace *trace, FILE *fp)
2981{
2982 struct stats *stats;
2983 size_t printed = 0;
2984 struct syscall *sc;
2985 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2986
2987 if (inode == NULL)
2988 return 0;
2989
2990 printed += fprintf(fp, "\n");
2991
Milian Wolff834fd462015-08-06 11:24:29 +02002992 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2993 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2994 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002995
David Ahernbf2575c2013-10-08 21:26:53 -06002996 /* each int_node is a syscall */
2997 while (inode) {
2998 stats = inode->priv;
2999 if (stats) {
3000 double min = (double)(stats->min) / NSEC_PER_MSEC;
3001 double max = (double)(stats->max) / NSEC_PER_MSEC;
3002 double avg = avg_stats(stats);
3003 double pct;
3004 u64 n = (u64) stats->n;
3005
3006 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
3007 avg /= NSEC_PER_MSEC;
3008
3009 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02003010 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02003011 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
3012 n, avg * n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02003013 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06003014 }
3015
3016 inode = intlist__next(inode);
3017 }
3018
3019 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003020
3021 return printed;
3022}
3023
David Ahern896cbb52013-09-28 13:12:59 -06003024/* struct used to pass data to per-thread function */
3025struct summary_data {
3026 FILE *fp;
3027 struct trace *trace;
3028 size_t printed;
3029};
3030
3031static int trace__fprintf_one_thread(struct thread *thread, void *priv)
3032{
3033 struct summary_data *data = priv;
3034 FILE *fp = data->fp;
3035 size_t printed = data->printed;
3036 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09003037 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06003038 double ratio;
3039
3040 if (ttrace == NULL)
3041 return 0;
3042
3043 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
3044
Pekka Enberg15e65c62013-11-14 18:43:30 +02003045 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003046 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02003047 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04003048 if (ttrace->pfmaj)
3049 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
3050 if (ttrace->pfmin)
3051 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003052 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06003053 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06003054
3055 data->printed += printed;
3056
3057 return 0;
3058}
3059
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003060static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
3061{
David Ahern896cbb52013-09-28 13:12:59 -06003062 struct summary_data data = {
3063 .fp = fp,
3064 .trace = trace
3065 };
3066 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003067
David Ahern896cbb52013-09-28 13:12:59 -06003068 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003069
David Ahern896cbb52013-09-28 13:12:59 -06003070 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003071}
3072
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003073static int trace__set_duration(const struct option *opt, const char *str,
3074 int unset __maybe_unused)
3075{
3076 struct trace *trace = opt->value;
3077
3078 trace->duration_filter = atof(str);
3079 return 0;
3080}
3081
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08003082static int trace__set_filter_pids(const struct option *opt, const char *str,
3083 int unset __maybe_unused)
3084{
3085 int ret = -1;
3086 size_t i;
3087 struct trace *trace = opt->value;
3088 /*
3089 * FIXME: introduce a intarray class, plain parse csv and create a
3090 * { int nr, int entries[] } struct...
3091 */
3092 struct intlist *list = intlist__new(str);
3093
3094 if (list == NULL)
3095 return -1;
3096
3097 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
3098 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
3099
3100 if (trace->filter_pids.entries == NULL)
3101 goto out;
3102
3103 trace->filter_pids.entries[0] = getpid();
3104
3105 for (i = 1; i < trace->filter_pids.nr; ++i)
3106 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
3107
3108 intlist__delete(list);
3109 ret = 0;
3110out:
3111 return ret;
3112}
3113
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003114static int trace__open_output(struct trace *trace, const char *filename)
3115{
3116 struct stat st;
3117
3118 if (!stat(filename, &st) && st.st_size) {
3119 char oldname[PATH_MAX];
3120
3121 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
3122 unlink(oldname);
3123 rename(filename, oldname);
3124 }
3125
3126 trace->output = fopen(filename, "w");
3127
3128 return trace->output == NULL ? -errno : 0;
3129}
3130
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003131static int parse_pagefaults(const struct option *opt, const char *str,
3132 int unset __maybe_unused)
3133{
3134 int *trace_pgfaults = opt->value;
3135
3136 if (strcmp(str, "all") == 0)
3137 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
3138 else if (strcmp(str, "maj") == 0)
3139 *trace_pgfaults |= TRACE_PFMAJ;
3140 else if (strcmp(str, "min") == 0)
3141 *trace_pgfaults |= TRACE_PFMIN;
3142 else
3143 return -1;
3144
3145 return 0;
3146}
3147
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003148static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3149{
3150 struct perf_evsel *evsel;
3151
3152 evlist__for_each(evlist, evsel)
3153 evsel->handler = handler;
3154}
3155
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003156int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3157{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003158 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003159 "perf trace [<options>] [<command>]",
3160 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003161 "perf trace record [<options>] [<command>]",
3162 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003163 NULL
3164 };
3165 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003166 .audit = {
3167 .machine = audit_detect_machine(),
3168 .open_id = audit_name_to_syscall("open", trace.audit.machine),
3169 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003170 .syscalls = {
3171 . max = -1,
3172 },
3173 .opts = {
3174 .target = {
3175 .uid = UINT_MAX,
3176 .uses_mmap = true,
3177 },
3178 .user_freq = UINT_MAX,
3179 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003180 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003181 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003182 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003183 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003184 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003185 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003186 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003187 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003188 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003189 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003190 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003191 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3192 "event selector. use 'perf list' to list available events",
3193 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003194 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3195 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003196 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03003197 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003198 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003199 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003200 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3201 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003202 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003203 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003204 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3205 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003206 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003207 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003208 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003209 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003210 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003211 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003212 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3213 "number of mmap data pages",
3214 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003215 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003216 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003217 OPT_CALLBACK(0, "duration", &trace, "float",
3218 "show only events with duration > N.M ms",
3219 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003220 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003221 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003222 OPT_BOOLEAN('T', "time", &trace.full_time,
3223 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003224 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3225 "Show only syscall summary with statistics"),
3226 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3227 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003228 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3229 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003230 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003231 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003232 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3233 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003234 OPT_END()
3235 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003236 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003237 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003238 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003239
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003240 signal(SIGSEGV, sighandler_dump_stack);
3241 signal(SIGFPE, sighandler_dump_stack);
3242
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003243 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003244
3245 if (trace.evlist == NULL) {
3246 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003247 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003248 goto out;
3249 }
3250
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003251 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3252 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003253
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003254 if (trace.trace_pgfaults) {
3255 trace.opts.sample_address = true;
3256 trace.opts.sample_time = true;
3257 }
3258
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003259 if (trace.evlist->nr_entries > 0)
3260 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3261
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003262 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3263 return trace__record(&trace, argc-1, &argv[1]);
3264
3265 /* summary_only implies summary option, but don't overwrite summary if set */
3266 if (trace.summary_only)
3267 trace.summary = trace.summary_only;
3268
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003269 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3270 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003271 pr_err("Please specify something to trace.\n");
3272 return -1;
3273 }
3274
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003275 if (output_name != NULL) {
3276 err = trace__open_output(&trace, output_name);
3277 if (err < 0) {
3278 perror("failed to create output file");
3279 goto out;
3280 }
3281 }
3282
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003283 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003284 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03003285 struct strlist_config slist_config = {
3286 .dirname = system_path(STRACE_GROUPS_DIR),
3287 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003288
3289 trace.not_ev_qualifier = *s == '!';
3290 if (trace.not_ev_qualifier)
3291 ++s;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03003292 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003293 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003294 fputs("Not enough memory to parse event qualifier",
3295 trace.output);
3296 err = -ENOMEM;
3297 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003298 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003299
3300 err = trace__validate_ev_qualifier(&trace);
3301 if (err)
3302 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003303 }
3304
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003305 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003306 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003307 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003308 fprintf(trace.output, "%s", bf);
3309 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003310 }
3311
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003312 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003313 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003314 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003315 fprintf(trace.output, "%s", bf);
3316 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003317 }
3318
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003319 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003320 trace.opts.target.system_wide = true;
3321
David Ahern6810fc92013-08-28 22:29:52 -06003322 if (input_name)
3323 err = trace__replay(&trace);
3324 else
3325 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003326
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003327out_close:
3328 if (output_name != NULL)
3329 fclose(trace.output);
3330out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003331 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003332}