blob: 99daeed55a9b8c2af8e3f1a552d94983fc1b81ae [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 Ahern55d43bc2015-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 Ahern55d43bc2015-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 Melo514f1c62012-09-26 20:05:56 -03001076static struct syscall_fmt {
1077 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001078 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001079 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001080 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001081 bool errmsg;
1082 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001083 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001084} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -03001085 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001086 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1087 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001088 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -03001089 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001090 { .name = "brk", .hexret = true,
1091 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001092 { .name = "chdir", .errmsg = true,
1093 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1094 { .name = "chmod", .errmsg = true,
1095 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1096 { .name = "chroot", .errmsg = true,
1097 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -06001098 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001099 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001100 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -03001101 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001102 { .name = "creat", .errmsg = true,
1103 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001104 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001105 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001106 { .name = "dup2", .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 = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001109 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001110 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -03001111 { .name = "eventfd2", .errmsg = true,
1112 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001113 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001114 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1115 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001116 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001117 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001118 { .name = "fallocate", .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 = "fchdir", .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 = "fchmod", .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 = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001125 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1126 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001127 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001128 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001129 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001130 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1131 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001132 { .name = "fcntl", .errmsg = true,
1133 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1134 [1] = SCA_STRARRAY, /* cmd */ },
1135 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1136 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001137 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -03001138 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001139 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1140 [1] = SCA_FLOCK, /* cmd */ }, },
1141 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001142 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001143 { .name = "fstat", .errmsg = true, .alias = "newfstat",
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 = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001146 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1147 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001148 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001149 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001150 { .name = "fsync", .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 = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001153 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -03001154 { .name = "futex", .errmsg = true,
1155 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001156 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001157 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1158 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001159 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001160 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001161 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001162 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001163 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -03001164 { .name = "getrandom", .errmsg = true,
1165 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001166 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001167 { .name = "getxattr", .errmsg = true,
1168 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1169 { .name = "inotify_add_watch", .errmsg = true,
1170 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001171 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001172 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001173#if defined(__i386__) || defined(__x86_64__)
1174/*
1175 * FIXME: Make this available to all arches.
1176 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001177 [1] = SCA_STRHEXARRAY, /* cmd */
1178 [2] = SCA_HEX, /* arg */ },
1179 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001180#else
1181 [2] = SCA_HEX, /* arg */ }, },
1182#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -03001183 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001184 { .name = "kill", .errmsg = true,
1185 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001186 { .name = "lchown", .errmsg = true,
1187 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1188 { .name = "lgetxattr", .errmsg = true,
1189 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001190 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001191 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001192 { .name = "listxattr", .errmsg = true,
1193 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001194 { .name = "llistxattr", .errmsg = true,
1195 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1196 { .name = "lremovexattr", .errmsg = true,
1197 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001198 { .name = "lseek", .errmsg = true,
1199 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1200 [2] = SCA_STRARRAY, /* whence */ },
1201 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001202 { .name = "lsetxattr", .errmsg = true,
1203 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001204 { .name = "lstat", .errmsg = true, .alias = "newlstat",
1205 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001206 { .name = "lsxattr", .errmsg = true,
1207 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001208 { .name = "madvise", .errmsg = true,
1209 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1210 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001211 { .name = "mkdir", .errmsg = true,
1212 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001213 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001214 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1215 [1] = SCA_FILENAME, /* pathname */ }, },
1216 { .name = "mknod", .errmsg = true,
1217 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001218 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001219 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1220 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001221 { .name = "mlock", .errmsg = true,
1222 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1223 { .name = "mlockall", .errmsg = true,
1224 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001225 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001226 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001227 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001228 [3] = SCA_MMAP_FLAGS, /* flags */
1229 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001230 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001231 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1232 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001233 { .name = "mq_unlink", .errmsg = true,
1234 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001235 { .name = "mremap", .hexret = true,
1236 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001237 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001238 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001239 { .name = "munlock", .errmsg = true,
1240 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001241 { .name = "munmap", .errmsg = true,
1242 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001243 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001244 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001245 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001246 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1247 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001248 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001249 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1250 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001251 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001252 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1253 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001254 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001255 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001256 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001257 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001258 { .name = "perf_event_open", .errmsg = true,
1259 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1260 [2] = SCA_INT, /* cpu */
1261 [3] = SCA_FD, /* group_fd */
1262 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001263 { .name = "pipe2", .errmsg = true,
1264 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001265 { .name = "poll", .errmsg = true, .timeout = true, },
1266 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001267 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001268 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001269 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001270 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001271 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001272 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001273 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001274 { .name = "pwritev", .errmsg = true,
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 = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001277 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001278 { .name = "readlink", .errmsg = true,
1279 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001280 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001281 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1282 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001283 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001284 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001285 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001286 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1287 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001288 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001289 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1290 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001291 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001292 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1293 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001294 { .name = "removexattr", .errmsg = true,
1295 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001296 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001297 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001298 { .name = "rmdir", .errmsg = true,
1299 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001300 { .name = "rt_sigaction", .errmsg = true,
1301 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001302 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001303 { .name = "rt_sigqueueinfo", .errmsg = true,
1304 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1305 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1306 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001307 { .name = "seccomp", .errmsg = true,
1308 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
1309 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001310 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001311 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001312 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1313 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001314 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001315 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1316 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001317 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001318 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1319 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001320 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1321 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001322 { .name = "setxattr", .errmsg = true,
1323 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001324 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001325 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001326 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001327 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1328 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001329 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001330 { .name = "socketpair", .errmsg = true,
1331 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1332 [1] = SCA_SK_TYPE, /* type */ },
1333 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001334 { .name = "stat", .errmsg = true, .alias = "newstat",
1335 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001336 { .name = "statfs", .errmsg = true,
1337 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1338 { .name = "swapoff", .errmsg = true,
1339 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1340 { .name = "swapon", .errmsg = true,
1341 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001342 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001343 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001344 { .name = "tgkill", .errmsg = true,
1345 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1346 { .name = "tkill", .errmsg = true,
1347 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001348 { .name = "truncate", .errmsg = true,
1349 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001350 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001351 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001352 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1353 [1] = SCA_FILENAME, /* pathname */ }, },
1354 { .name = "utime", .errmsg = true,
1355 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001356 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001357 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1358 [1] = SCA_FILENAME, /* filename */ }, },
1359 { .name = "utimes", .errmsg = true,
1360 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001361 { .name = "vmsplice", .errmsg = true,
1362 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001363 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001364 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001365 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001366 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001367};
1368
1369static int syscall_fmt__cmp(const void *name, const void *fmtp)
1370{
1371 const struct syscall_fmt *fmt = fmtp;
1372 return strcmp(name, fmt->name);
1373}
1374
1375static struct syscall_fmt *syscall_fmt__find(const char *name)
1376{
1377 const int nmemb = ARRAY_SIZE(syscall_fmts);
1378 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1379}
1380
1381struct syscall {
1382 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001383 int nr_args;
1384 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001385 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001386 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001387 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001388 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001389 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001390};
1391
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001392static size_t fprintf_duration(unsigned long t, FILE *fp)
1393{
1394 double duration = (double)t / NSEC_PER_MSEC;
1395 size_t printed = fprintf(fp, "(");
1396
1397 if (duration >= 1.0)
1398 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1399 else if (duration >= 0.01)
1400 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1401 else
1402 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001403 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001404}
1405
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001406/**
1407 * filename.ptr: The filename char pointer that will be vfs_getname'd
1408 * filename.entry_str_pos: Where to insert the string translated from
1409 * filename.ptr by the vfs_getname tracepoint/kprobe.
1410 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001411struct thread_trace {
1412 u64 entry_time;
1413 u64 exit_time;
1414 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001415 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001416 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001417 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001418 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001419 struct {
1420 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001421 short int entry_str_pos;
1422 bool pending_open;
1423 unsigned int namelen;
1424 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001425 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001426 struct {
1427 int max;
1428 char **table;
1429 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001430
1431 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001432};
1433
1434static struct thread_trace *thread_trace__new(void)
1435{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001436 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1437
1438 if (ttrace)
1439 ttrace->paths.max = -1;
1440
David Ahernbf2575c2013-10-08 21:26:53 -06001441 ttrace->syscall_stats = intlist__new(NULL);
1442
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001443 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001444}
1445
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001446static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001447{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001448 struct thread_trace *ttrace;
1449
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001450 if (thread == NULL)
1451 goto fail;
1452
Namhyung Kim89dceb22014-10-06 09:46:03 +09001453 if (thread__priv(thread) == NULL)
1454 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001455
Namhyung Kim89dceb22014-10-06 09:46:03 +09001456 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001457 goto fail;
1458
Namhyung Kim89dceb22014-10-06 09:46:03 +09001459 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001460 ++ttrace->nr_events;
1461
1462 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001463fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001464 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001465 "WARNING: not enough memory, dropping samples!\n");
1466 return NULL;
1467}
1468
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001469#define TRACE_PFMAJ (1 << 0)
1470#define TRACE_PFMIN (1 << 1)
1471
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001472static const size_t trace__entry_str_size = 2048;
1473
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001474struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001475 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001476 struct {
1477 int machine;
1478 int open_id;
1479 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001480 struct {
1481 int max;
1482 struct syscall *table;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001483 struct {
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001484 struct perf_evsel *sys_enter,
1485 *sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001486 } events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001487 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001488 struct record_opts opts;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001489 struct perf_evlist *evlist;
David Ahern8fb598e2013-09-28 13:13:00 -06001490 struct machine *host;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001491 struct thread *current;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001492 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001493 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001494 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001495 struct strlist *ev_qualifier;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001496 struct {
1497 size_t nr;
1498 int *entries;
1499 } ev_qualifier_ids;
David Ahernbdc89662013-08-28 22:29:53 -06001500 struct intlist *tid_list;
1501 struct intlist *pid_list;
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08001502 struct {
1503 size_t nr;
1504 pid_t *entries;
1505 } filter_pids;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001506 double duration_filter;
1507 double runtime_ms;
1508 struct {
1509 u64 vfs_getname,
1510 proc_getname;
1511 } stats;
1512 bool not_ev_qualifier;
1513 bool live;
1514 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001515 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001516 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001517 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001518 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001519 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001520 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001521 bool trace_syscalls;
Yunlong Songe366a6d2015-04-02 21:47:18 +08001522 bool force;
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03001523 bool vfs_getname;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001524 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001525};
1526
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001527static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001528{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001529 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001530
1531 if (fd > ttrace->paths.max) {
1532 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1533
1534 if (npath == NULL)
1535 return -1;
1536
1537 if (ttrace->paths.max != -1) {
1538 memset(npath + ttrace->paths.max + 1, 0,
1539 (fd - ttrace->paths.max) * sizeof(char *));
1540 } else {
1541 memset(npath, 0, (fd + 1) * sizeof(char *));
1542 }
1543
1544 ttrace->paths.table = npath;
1545 ttrace->paths.max = fd;
1546 }
1547
1548 ttrace->paths.table[fd] = strdup(pathname);
1549
1550 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1551}
1552
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001553static int thread__read_fd_path(struct thread *thread, int fd)
1554{
1555 char linkname[PATH_MAX], pathname[PATH_MAX];
1556 struct stat st;
1557 int ret;
1558
1559 if (thread->pid_ == thread->tid) {
1560 scnprintf(linkname, sizeof(linkname),
1561 "/proc/%d/fd/%d", thread->pid_, fd);
1562 } else {
1563 scnprintf(linkname, sizeof(linkname),
1564 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1565 }
1566
1567 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1568 return -1;
1569
1570 ret = readlink(linkname, pathname, sizeof(pathname));
1571
1572 if (ret < 0 || ret > st.st_size)
1573 return -1;
1574
1575 pathname[ret] = '\0';
1576 return trace__set_fd_pathname(thread, fd, pathname);
1577}
1578
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001579static const char *thread__fd_path(struct thread *thread, int fd,
1580 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001581{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001582 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001583
1584 if (ttrace == NULL)
1585 return NULL;
1586
1587 if (fd < 0)
1588 return NULL;
1589
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001590 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001591 if (!trace->live)
1592 return NULL;
1593 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001594 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001595 return NULL;
1596 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001597
1598 return ttrace->paths.table[fd];
1599}
1600
1601static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1602 struct syscall_arg *arg)
1603{
1604 int fd = arg->val;
1605 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001606 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001607
1608 if (path)
1609 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1610
1611 return printed;
1612}
1613
1614static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1615 struct syscall_arg *arg)
1616{
1617 int fd = arg->val;
1618 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001619 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001620
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001621 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1622 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001623
1624 return printed;
1625}
1626
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001627static void thread__set_filename_pos(struct thread *thread, const char *bf,
1628 unsigned long ptr)
1629{
1630 struct thread_trace *ttrace = thread__priv(thread);
1631
1632 ttrace->filename.ptr = ptr;
1633 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1634}
1635
1636static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1637 struct syscall_arg *arg)
1638{
1639 unsigned long ptr = arg->val;
1640
1641 if (!arg->trace->vfs_getname)
1642 return scnprintf(bf, size, "%#x", ptr);
1643
1644 thread__set_filename_pos(arg->thread, bf, ptr);
1645 return 0;
1646}
1647
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001648static bool trace__filter_duration(struct trace *trace, double t)
1649{
1650 return t < (trace->duration_filter * NSEC_PER_MSEC);
1651}
1652
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001653static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1654{
1655 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1656
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001657 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001658}
1659
Namhyung Kimf15eb532012-10-05 14:02:16 +09001660static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001661static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001662
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001663static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001664{
1665 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001666 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001667}
1668
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001669static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001670 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001671{
1672 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001673 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001674
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001675 if (trace->multiple_threads) {
1676 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001677 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001678 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001679 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001680
1681 return printed;
1682}
1683
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001684static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001685 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001686{
1687 int ret = 0;
1688
1689 switch (event->header.type) {
1690 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001691 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001692 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001693 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001694 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001695 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001696 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001697 break;
1698 }
1699
1700 return ret;
1701}
1702
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001703static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001704 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001705 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001706 struct machine *machine)
1707{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001708 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001709 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001710}
1711
1712static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1713{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001714 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001715
1716 if (err)
1717 return err;
1718
David Ahern8fb598e2013-09-28 13:13:00 -06001719 trace->host = machine__new_host();
1720 if (trace->host == NULL)
1721 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001722
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001723 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001724 return -errno;
1725
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001726 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001727 evlist->threads, trace__tool_process, false,
1728 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001729 if (err)
1730 symbol__exit();
1731
1732 return err;
1733}
1734
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001735static int syscall__set_arg_fmts(struct syscall *sc)
1736{
1737 struct format_field *field;
1738 int idx = 0;
1739
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001740 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001741 if (sc->arg_scnprintf == NULL)
1742 return -1;
1743
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001744 if (sc->fmt)
1745 sc->arg_parm = sc->fmt->arg_parm;
1746
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001747 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001748 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1749 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1750 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001751 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1752 ++idx;
1753 }
1754
1755 return 0;
1756}
1757
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001758static int trace__read_syscall_info(struct trace *trace, int id)
1759{
1760 char tp_name[128];
1761 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001762 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001763
1764 if (name == NULL)
1765 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001766
1767 if (id > trace->syscalls.max) {
1768 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1769
1770 if (nsyscalls == NULL)
1771 return -1;
1772
1773 if (trace->syscalls.max != -1) {
1774 memset(nsyscalls + trace->syscalls.max + 1, 0,
1775 (id - trace->syscalls.max) * sizeof(*sc));
1776 } else {
1777 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1778 }
1779
1780 trace->syscalls.table = nsyscalls;
1781 trace->syscalls.max = id;
1782 }
1783
1784 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001785 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001786
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001787 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001788
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001789 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001790 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001791
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001792 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001793 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
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 }
1796
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001797 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001798 return -1;
1799
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001800 sc->args = sc->tp_format->format.fields;
1801 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001802 /*
1803 * We need to check and discard the first variable '__syscall_nr'
1804 * or 'nr' that mean the syscall number. It is needless here.
1805 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1806 */
1807 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001808 sc->args = sc->args->next;
1809 --sc->nr_args;
1810 }
1811
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001812 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1813
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001814 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001815}
1816
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001817static int trace__validate_ev_qualifier(struct trace *trace)
1818{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001819 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001820 struct str_node *pos;
1821
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001822 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1823 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1824 sizeof(trace->ev_qualifier_ids.entries[0]));
1825
1826 if (trace->ev_qualifier_ids.entries == NULL) {
1827 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1828 trace->output);
1829 err = -EINVAL;
1830 goto out;
1831 }
1832
1833 i = 0;
1834
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001835 strlist__for_each(pos, trace->ev_qualifier) {
1836 const char *sc = pos->s;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001837 int id = audit_name_to_syscall(sc, trace->audit.machine);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001838
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001839 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001840 if (err == 0) {
1841 fputs("Error:\tInvalid syscall ", trace->output);
1842 err = -EINVAL;
1843 } else {
1844 fputs(", ", trace->output);
1845 }
1846
1847 fputs(sc, trace->output);
1848 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001849
1850 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001851 }
1852
1853 if (err < 0) {
1854 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1855 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001856 zfree(&trace->ev_qualifier_ids.entries);
1857 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001858 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001859out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001860 return err;
1861}
1862
David Ahern55d43bc2015-02-19 15:00:22 -05001863/*
1864 * args is to be interpreted as a series of longs but we need to handle
1865 * 8-byte unaligned accesses. args points to raw_data within the event
1866 * and raw_data is guaranteed to be 8-byte unaligned because it is
1867 * preceded by raw_size which is a u32. So we need to copy args to a temp
1868 * variable to read it. Most notably this avoids extended load instructions
1869 * on unaligned addresses
1870 */
1871
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001872static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001873 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001874 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001875{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001876 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001877 unsigned char *p;
1878 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001879
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001880 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001881 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001882 u8 bit = 1;
1883 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001884 .idx = 0,
1885 .mask = 0,
1886 .trace = trace,
1887 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001888 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001889
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001890 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001891 field = field->next, ++arg.idx, bit <<= 1) {
1892 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001893 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001894
1895 /* special care for unaligned accesses */
1896 p = args + sizeof(unsigned long) * arg.idx;
1897 memcpy(&val, p, sizeof(val));
1898
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001899 /*
1900 * Suppress this argument if its value is zero and
1901 * and we don't have a string associated in an
1902 * strarray for it.
1903 */
David Ahern55d43bc2015-02-19 15:00:22 -05001904 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001905 !(sc->arg_scnprintf &&
1906 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1907 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001908 continue;
1909
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001910 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001911 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001912 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001913 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001914 if (sc->arg_parm)
1915 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001916 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1917 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001918 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001919 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001920 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001921 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001922 }
1923 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001924 int i = 0;
1925
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001926 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001927 /* special care for unaligned accesses */
1928 p = args + sizeof(unsigned long) * i;
1929 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001930 printed += scnprintf(bf + printed, size - printed,
1931 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001932 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001933 ++i;
1934 }
1935 }
1936
1937 return printed;
1938}
1939
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001940typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001941 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001942 struct perf_sample *sample);
1943
1944static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001945 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001946{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001947
1948 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001949
1950 /*
1951 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1952 * before that, leaving at a higher verbosity level till that is
1953 * explained. Reproduced with plain ftrace with:
1954 *
1955 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1956 * grep "NR -1 " /t/trace_pipe
1957 *
1958 * After generating some load on the machine.
1959 */
1960 if (verbose > 1) {
1961 static u64 n;
1962 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1963 id, perf_evsel__name(evsel), ++n);
1964 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001965 return NULL;
1966 }
1967
1968 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1969 trace__read_syscall_info(trace, id))
1970 goto out_cant_read;
1971
1972 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1973 goto out_cant_read;
1974
1975 return &trace->syscalls.table[id];
1976
1977out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001978 if (verbose) {
1979 fprintf(trace->output, "Problems reading syscall %d", id);
1980 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1981 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1982 fputs(" information\n", trace->output);
1983 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001984 return NULL;
1985}
1986
David Ahernbf2575c2013-10-08 21:26:53 -06001987static void thread__update_stats(struct thread_trace *ttrace,
1988 int id, struct perf_sample *sample)
1989{
1990 struct int_node *inode;
1991 struct stats *stats;
1992 u64 duration = 0;
1993
1994 inode = intlist__findnew(ttrace->syscall_stats, id);
1995 if (inode == NULL)
1996 return;
1997
1998 stats = inode->priv;
1999 if (stats == NULL) {
2000 stats = malloc(sizeof(struct stats));
2001 if (stats == NULL)
2002 return;
2003 init_stats(stats);
2004 inode->priv = stats;
2005 }
2006
2007 if (ttrace->entry_time && sample->time > ttrace->entry_time)
2008 duration = sample->time - ttrace->entry_time;
2009
2010 update_stats(stats, duration);
2011}
2012
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03002013static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
2014{
2015 struct thread_trace *ttrace;
2016 u64 duration;
2017 size_t printed;
2018
2019 if (trace->current == NULL)
2020 return 0;
2021
2022 ttrace = thread__priv(trace->current);
2023
2024 if (!ttrace->entry_pending)
2025 return 0;
2026
2027 duration = sample->time - ttrace->entry_time;
2028
2029 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
2030 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
2031 ttrace->entry_pending = false;
2032
2033 return printed;
2034}
2035
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002036static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002037 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002038 struct perf_sample *sample)
2039{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002040 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002041 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002042 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002043 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002044 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002045 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002046 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002047
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002048 if (sc == NULL)
2049 return -1;
2050
David Ahern8fb598e2013-09-28 13:13:00 -06002051 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002052 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002053 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002054 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002055
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002056 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002057
2058 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002059 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002060 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002061 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002062 }
2063
David Ahern13f22a22015-03-19 12:23:03 -06002064 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03002065 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03002066
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002067 ttrace->entry_time = sample->time;
2068 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002069 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002070
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002071 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002072 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002073
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03002074 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07002075 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002076 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
2077 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002078 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002079 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002080 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002081 /* See trace__vfs_getname & trace__sys_exit */
2082 ttrace->filename.pending_open = false;
2083 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002084
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002085 if (trace->current != thread) {
2086 thread__put(trace->current);
2087 trace->current = thread__get(thread);
2088 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002089 err = 0;
2090out_put:
2091 thread__put(thread);
2092 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002093}
2094
2095static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002096 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002097 struct perf_sample *sample)
2098{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002099 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002100 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002101 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002102 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002103 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002104 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002105
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002106 if (sc == NULL)
2107 return -1;
2108
David Ahern8fb598e2013-09-28 13:13:00 -06002109 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002110 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002111 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002112 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002113
David Ahernbf2575c2013-10-08 21:26:53 -06002114 if (trace->summary)
2115 thread__update_stats(ttrace, id, sample);
2116
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002117 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002118
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002119 if (id == trace->audit.open_id && ret >= 0 && ttrace->filename.pending_open) {
2120 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
2121 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002122 ++trace->stats.vfs_getname;
2123 }
2124
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002125 ttrace->exit_time = sample->time;
2126
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002127 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002128 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002129 if (trace__filter_duration(trace, duration))
2130 goto out;
2131 } else if (trace->duration_filter)
2132 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002133
David Ahernfd2eaba2013-11-12 09:31:15 -07002134 if (trace->summary_only)
2135 goto out;
2136
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002137 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002138
2139 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002140 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002141 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002142 fprintf(trace->output, " ... [");
2143 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
2144 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002145 }
2146
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002147 if (sc->fmt == NULL) {
2148signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002149 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002150 } else if (ret < 0 && sc->fmt->errmsg) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00002151 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002152 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
2153 *e = audit_errno_to_name(-ret);
2154
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002155 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002156 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002157 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03002158 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002159 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002160 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002161 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002162
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002163 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002164out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002165 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002166 err = 0;
2167out_put:
2168 thread__put(thread);
2169 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002170}
2171
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002172static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002173 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002174 struct perf_sample *sample)
2175{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002176 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2177 struct thread_trace *ttrace;
2178 size_t filename_len, entry_str_len, to_move;
2179 ssize_t remaining_space;
2180 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002181 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002182
2183 if (!thread)
2184 goto out;
2185
2186 ttrace = thread__priv(thread);
2187 if (!ttrace)
2188 goto out;
2189
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002190 filename_len = strlen(filename);
2191
2192 if (ttrace->filename.namelen < filename_len) {
2193 char *f = realloc(ttrace->filename.name, filename_len + 1);
2194
2195 if (f == NULL)
2196 goto out;
2197
2198 ttrace->filename.namelen = filename_len;
2199 ttrace->filename.name = f;
2200 }
2201
2202 strcpy(ttrace->filename.name, filename);
2203 ttrace->filename.pending_open = true;
2204
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002205 if (!ttrace->filename.ptr)
2206 goto out;
2207
2208 entry_str_len = strlen(ttrace->entry_str);
2209 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2210 if (remaining_space <= 0)
2211 goto out;
2212
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002213 if (filename_len > (size_t)remaining_space) {
2214 filename += filename_len - remaining_space;
2215 filename_len = remaining_space;
2216 }
2217
2218 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2219 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2220 memmove(pos + filename_len, pos, to_move);
2221 memcpy(pos, filename, filename_len);
2222
2223 ttrace->filename.ptr = 0;
2224 ttrace->filename.entry_str_pos = 0;
2225out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002226 return 0;
2227}
2228
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002229static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002230 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002231 struct perf_sample *sample)
2232{
2233 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2234 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06002235 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03002236 sample->pid,
2237 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002238 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002239
2240 if (ttrace == NULL)
2241 goto out_dump;
2242
2243 ttrace->runtime_ms += runtime_ms;
2244 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002245 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002246 return 0;
2247
2248out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002249 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002250 evsel->name,
2251 perf_evsel__strval(evsel, sample, "comm"),
2252 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2253 runtime,
2254 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002255 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002256 return 0;
2257}
2258
Wang Nan1d6c9402016-02-26 09:31:55 +00002259static void bpf_output__printer(enum binary_printer_ops op,
2260 unsigned int val, void *extra)
2261{
2262 FILE *output = extra;
2263 unsigned char ch = (unsigned char)val;
2264
2265 switch (op) {
2266 case BINARY_PRINT_CHAR_DATA:
2267 fprintf(output, "%c", isprint(ch) ? ch : '.');
2268 break;
2269 case BINARY_PRINT_DATA_BEGIN:
2270 case BINARY_PRINT_LINE_BEGIN:
2271 case BINARY_PRINT_ADDR:
2272 case BINARY_PRINT_NUM_DATA:
2273 case BINARY_PRINT_NUM_PAD:
2274 case BINARY_PRINT_SEP:
2275 case BINARY_PRINT_CHAR_PAD:
2276 case BINARY_PRINT_LINE_END:
2277 case BINARY_PRINT_DATA_END:
2278 default:
2279 break;
2280 }
2281}
2282
2283static void bpf_output__fprintf(struct trace *trace,
2284 struct perf_sample *sample)
2285{
2286 print_binary(sample->raw_data, sample->raw_size, 8,
2287 bpf_output__printer, trace->output);
2288}
2289
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002290static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2291 union perf_event *event __maybe_unused,
2292 struct perf_sample *sample)
2293{
2294 trace__printf_interrupted_entry(trace, sample);
2295 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002296
2297 if (trace->trace_syscalls)
2298 fprintf(trace->output, "( ): ");
2299
2300 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002301
Wang Nan1d6c9402016-02-26 09:31:55 +00002302 if (perf_evsel__is_bpf_output(evsel)) {
2303 bpf_output__fprintf(trace, sample);
2304 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002305 event_format__fprintf(evsel->tp_format, sample->cpu,
2306 sample->raw_data, sample->raw_size,
2307 trace->output);
2308 }
2309
2310 fprintf(trace->output, ")\n");
2311 return 0;
2312}
2313
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002314static void print_location(FILE *f, struct perf_sample *sample,
2315 struct addr_location *al,
2316 bool print_dso, bool print_sym)
2317{
2318
2319 if ((verbose || print_dso) && al->map)
2320 fprintf(f, "%s@", al->map->dso->long_name);
2321
2322 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002323 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002324 al->addr - al->sym->start);
2325 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002326 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002327 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002328 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002329}
2330
2331static int trace__pgfault(struct trace *trace,
2332 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002333 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002334 struct perf_sample *sample)
2335{
2336 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002337 struct addr_location al;
2338 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002339 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002340 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002341
2342 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002343 ttrace = thread__trace(thread, trace->output);
2344 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002345 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002346
2347 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2348 ttrace->pfmaj++;
2349 else
2350 ttrace->pfmin++;
2351
2352 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002353 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002354
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002355 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002356 sample->ip, &al);
2357
2358 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2359
2360 fprintf(trace->output, "%sfault [",
2361 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2362 "maj" : "min");
2363
2364 print_location(trace->output, sample, &al, false, true);
2365
2366 fprintf(trace->output, "] => ");
2367
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002368 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002369 sample->addr, &al);
2370
2371 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002372 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002373 MAP__FUNCTION, sample->addr, &al);
2374
2375 if (al.map)
2376 map_type = 'x';
2377 else
2378 map_type = '?';
2379 }
2380
2381 print_location(trace->output, sample, &al, true, false);
2382
2383 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002384out:
2385 err = 0;
2386out_put:
2387 thread__put(thread);
2388 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002389}
2390
David Ahernbdc89662013-08-28 22:29:53 -06002391static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2392{
2393 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2394 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2395 return false;
2396
2397 if (trace->pid_list || trace->tid_list)
2398 return true;
2399
2400 return false;
2401}
2402
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002403static void trace__set_base_time(struct trace *trace,
2404 struct perf_evsel *evsel __maybe_unused,
2405 struct perf_sample *sample)
2406{
2407 if (trace->base_time == 0 && !trace->full_time)
2408 trace->base_time = sample->time;
2409}
2410
David Ahern6810fc92013-08-28 22:29:52 -06002411static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002412 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002413 struct perf_sample *sample,
2414 struct perf_evsel *evsel,
2415 struct machine *machine __maybe_unused)
2416{
2417 struct trace *trace = container_of(tool, struct trace, tool);
2418 int err = 0;
2419
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002420 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002421
David Ahernbdc89662013-08-28 22:29:53 -06002422 if (skip_sample(trace, sample))
2423 return 0;
2424
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002425 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002426
David Ahern31605652013-12-04 19:41:41 -07002427 if (handler) {
2428 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002429 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002430 }
David Ahern6810fc92013-08-28 22:29:52 -06002431
2432 return err;
2433}
2434
David Ahernbdc89662013-08-28 22:29:53 -06002435static int parse_target_str(struct trace *trace)
2436{
2437 if (trace->opts.target.pid) {
2438 trace->pid_list = intlist__new(trace->opts.target.pid);
2439 if (trace->pid_list == NULL) {
2440 pr_err("Error parsing process id string\n");
2441 return -EINVAL;
2442 }
2443 }
2444
2445 if (trace->opts.target.tid) {
2446 trace->tid_list = intlist__new(trace->opts.target.tid);
2447 if (trace->tid_list == NULL) {
2448 pr_err("Error parsing thread id string\n");
2449 return -EINVAL;
2450 }
2451 }
2452
2453 return 0;
2454}
2455
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002456static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002457{
2458 unsigned int rec_argc, i, j;
2459 const char **rec_argv;
2460 const char * const record_args[] = {
2461 "record",
2462 "-R",
2463 "-m", "1024",
2464 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002465 };
2466
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002467 const char * const sc_args[] = { "-e", };
2468 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2469 const char * const majpf_args[] = { "-e", "major-faults" };
2470 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2471 const char * const minpf_args[] = { "-e", "minor-faults" };
2472 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2473
David Ahern9aca7f12013-12-04 19:41:39 -07002474 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002475 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2476 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002477 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2478
2479 if (rec_argv == NULL)
2480 return -ENOMEM;
2481
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002482 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002483 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002484 rec_argv[j++] = record_args[i];
2485
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002486 if (trace->trace_syscalls) {
2487 for (i = 0; i < sc_args_nr; i++)
2488 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002489
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002490 /* event string may be different for older kernels - e.g., RHEL6 */
2491 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2492 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2493 else if (is_valid_tracepoint("syscalls:sys_enter"))
2494 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2495 else {
2496 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2497 return -1;
2498 }
David Ahern9aca7f12013-12-04 19:41:39 -07002499 }
David Ahern9aca7f12013-12-04 19:41:39 -07002500
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002501 if (trace->trace_pgfaults & TRACE_PFMAJ)
2502 for (i = 0; i < majpf_args_nr; i++)
2503 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002504
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002505 if (trace->trace_pgfaults & TRACE_PFMIN)
2506 for (i = 0; i < minpf_args_nr; i++)
2507 rec_argv[j++] = minpf_args[i];
2508
2509 for (i = 0; i < (unsigned int)argc; i++)
2510 rec_argv[j++] = argv[i];
2511
2512 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002513}
2514
David Ahernbf2575c2013-10-08 21:26:53 -06002515static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2516
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002517static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002518{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002519 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002520
2521 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002522 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002523
2524 if (perf_evsel__field(evsel, "pathname") == NULL) {
2525 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002526 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002527 }
2528
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002529 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002530 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002531 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002532}
2533
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002534static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2535 u64 config)
2536{
2537 struct perf_evsel *evsel;
2538 struct perf_event_attr attr = {
2539 .type = PERF_TYPE_SOFTWARE,
2540 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002541 };
2542
2543 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002544 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002545
2546 event_attr_init(&attr);
2547
2548 evsel = perf_evsel__new(&attr);
2549 if (!evsel)
2550 return -ENOMEM;
2551
2552 evsel->handler = trace__pgfault;
2553 perf_evlist__add(evlist, evsel);
2554
2555 return 0;
2556}
2557
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002558static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2559{
2560 const u32 type = event->header.type;
2561 struct perf_evsel *evsel;
2562
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002563 if (type != PERF_RECORD_SAMPLE) {
2564 trace__process_event(trace, trace->host, event, sample);
2565 return;
2566 }
2567
2568 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2569 if (evsel == NULL) {
2570 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2571 return;
2572 }
2573
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002574 trace__set_base_time(trace, evsel, sample);
2575
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002576 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2577 sample->raw_data == NULL) {
2578 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2579 perf_evsel__name(evsel), sample->tid,
2580 sample->cpu, sample->raw_size);
2581 } else {
2582 tracepoint_handler handler = evsel->handler;
2583 handler(trace, evsel, event, sample);
2584 }
2585}
2586
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002587static int trace__add_syscall_newtp(struct trace *trace)
2588{
2589 int ret = -1;
2590 struct perf_evlist *evlist = trace->evlist;
2591 struct perf_evsel *sys_enter, *sys_exit;
2592
2593 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2594 if (sys_enter == NULL)
2595 goto out;
2596
2597 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2598 goto out_delete_sys_enter;
2599
2600 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2601 if (sys_exit == NULL)
2602 goto out_delete_sys_enter;
2603
2604 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2605 goto out_delete_sys_exit;
2606
2607 perf_evlist__add(evlist, sys_enter);
2608 perf_evlist__add(evlist, sys_exit);
2609
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002610 trace->syscalls.events.sys_enter = sys_enter;
2611 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002612
2613 ret = 0;
2614out:
2615 return ret;
2616
2617out_delete_sys_exit:
2618 perf_evsel__delete_priv(sys_exit);
2619out_delete_sys_enter:
2620 perf_evsel__delete_priv(sys_enter);
2621 goto out;
2622}
2623
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002624static int trace__set_ev_qualifier_filter(struct trace *trace)
2625{
2626 int err = -1;
2627 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2628 trace->ev_qualifier_ids.nr,
2629 trace->ev_qualifier_ids.entries);
2630
2631 if (filter == NULL)
2632 goto out_enomem;
2633
2634 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2635 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2636
2637 free(filter);
2638out:
2639 return err;
2640out_enomem:
2641 errno = ENOMEM;
2642 goto out;
2643}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002644
Namhyung Kimf15eb532012-10-05 14:02:16 +09002645static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002646{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002647 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002648 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002649 int err = -1, i;
2650 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002651 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002652 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002653
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002654 trace->live = true;
2655
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002656 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002657 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002658
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002659 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002660 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002661
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002662 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002663 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002664 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002665 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002666
2667 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2668 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002669 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002670
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002671 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002672 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2673 trace__sched_stat_runtime))
2674 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002675
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002676 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2677 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002678 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002679 goto out_delete_evlist;
2680 }
2681
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002682 err = trace__symbols_init(trace, evlist);
2683 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002684 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002685 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002686 }
2687
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002688 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002689
Namhyung Kimf15eb532012-10-05 14:02:16 +09002690 signal(SIGCHLD, sig_handler);
2691 signal(SIGINT, sig_handler);
2692
2693 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002694 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002695 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002696 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002697 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002698 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002699 }
2700 }
2701
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002702 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002703 if (err < 0)
2704 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002705
Wang Nanba504232016-02-26 09:31:54 +00002706 err = bpf__apply_obj_config();
2707 if (err) {
2708 char errbuf[BUFSIZ];
2709
2710 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2711 pr_err("ERROR: Apply config to BPF failed: %s\n",
2712 errbuf);
2713 goto out_error_open;
2714 }
2715
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002716 /*
2717 * Better not use !target__has_task() here because we need to cover the
2718 * case where no threads were specified in the command line, but a
2719 * workload was, and in that case we will fill in the thread_map when
2720 * we fork the workload in perf_evlist__prepare_workload.
2721 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002722 if (trace->filter_pids.nr > 0)
2723 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002724 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002725 err = perf_evlist__set_filter_pid(evlist, getpid());
2726
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002727 if (err < 0)
2728 goto out_error_mem;
2729
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002730 if (trace->ev_qualifier_ids.nr > 0) {
2731 err = trace__set_ev_qualifier_filter(trace);
2732 if (err < 0)
2733 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002734
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002735 pr_debug("event qualifier tracepoint filter: %s\n",
2736 trace->syscalls.events.sys_exit->filter);
2737 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002738
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002739 err = perf_evlist__apply_filters(evlist, &evsel);
2740 if (err < 0)
2741 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002742
Jiri Olsaf8850372013-11-28 17:57:22 +01002743 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002744 if (err < 0)
2745 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002746
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002747 if (!target__none(&trace->opts.target))
2748 perf_evlist__enable(evlist);
2749
Namhyung Kimf15eb532012-10-05 14:02:16 +09002750 if (forks)
2751 perf_evlist__start_workload(evlist);
2752
Jiri Olsae13798c2015-06-23 00:36:02 +02002753 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002754 evlist->threads->nr > 1 ||
2755 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002756again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002757 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002758
2759 for (i = 0; i < evlist->nr_mmaps; i++) {
2760 union perf_event *event;
2761
2762 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002763 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002764
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002765 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002766
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002767 err = perf_evlist__parse_sample(evlist, event, &sample);
2768 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002769 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002770 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002771 }
2772
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002773 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002774next_event:
2775 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002776
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002777 if (interrupted)
2778 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002779
2780 if (done && !draining) {
2781 perf_evlist__disable(evlist);
2782 draining = true;
2783 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002784 }
2785 }
2786
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002787 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002788 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002789
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002790 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2791 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2792 draining = true;
2793
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002794 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002795 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002796 } else {
2797 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002798 }
2799
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002800out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002801 thread__zput(trace->current);
2802
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002803 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002804
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002805 if (!err) {
2806 if (trace->summary)
2807 trace__fprintf_thread_summary(trace, trace->output);
2808
2809 if (trace->show_tool_stats) {
2810 fprintf(trace->output, "Stats:\n "
2811 " vfs_getname : %" PRIu64 "\n"
2812 " proc_getname: %" PRIu64 "\n",
2813 trace->stats.vfs_getname,
2814 trace->stats.proc_getname);
2815 }
2816 }
David Ahernbf2575c2013-10-08 21:26:53 -06002817
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002818out_delete_evlist:
2819 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002820 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002821 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002822 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002823{
2824 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002825
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002826out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002827 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002828 goto out_error;
2829
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002830out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002831 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002832 goto out_error;
2833
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002834out_error_mmap:
2835 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2836 goto out_error;
2837
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002838out_error_open:
2839 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2840
2841out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002842 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302843 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002844
2845out_error_apply_filters:
2846 fprintf(trace->output,
2847 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2848 evsel->filter, perf_evsel__name(evsel), errno,
2849 strerror_r(errno, errbuf, sizeof(errbuf)));
2850 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002851}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002852out_error_mem:
2853 fprintf(trace->output, "Not enough memory to run!\n");
2854 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002855
2856out_errno:
2857 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2858 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002859}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002860
David Ahern6810fc92013-08-28 22:29:52 -06002861static int trace__replay(struct trace *trace)
2862{
2863 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002864 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002865 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002866 struct perf_data_file file = {
2867 .path = input_name,
2868 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002869 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002870 };
David Ahern6810fc92013-08-28 22:29:52 -06002871 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002872 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002873 int err = -1;
2874
2875 trace->tool.sample = trace__process_sample;
2876 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002877 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002878 trace->tool.comm = perf_event__process_comm;
2879 trace->tool.exit = perf_event__process_exit;
2880 trace->tool.fork = perf_event__process_fork;
2881 trace->tool.attr = perf_event__process_attr;
2882 trace->tool.tracing_data = perf_event__process_tracing_data;
2883 trace->tool.build_id = perf_event__process_build_id;
2884
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002885 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002886 trace->tool.ordering_requires_timestamps = true;
2887
2888 /* add tid to output */
2889 trace->multiple_threads = true;
2890
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002891 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002892 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002893 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002894
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002895 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002896 goto out;
2897
David Ahern8fb598e2013-09-28 13:13:00 -06002898 trace->host = &session->machines.host;
2899
David Ahern6810fc92013-08-28 22:29:52 -06002900 err = perf_session__set_tracepoints_handlers(session, handlers);
2901 if (err)
2902 goto out;
2903
Namhyung Kim003824e2013-11-12 15:25:00 +09002904 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2905 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002906 /* older kernels have syscalls tp versus raw_syscalls */
2907 if (evsel == NULL)
2908 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2909 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002910
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002911 if (evsel &&
2912 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2913 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002914 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2915 goto out;
2916 }
2917
2918 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2919 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002920 if (evsel == NULL)
2921 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2922 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002923 if (evsel &&
2924 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2925 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002926 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002927 goto out;
2928 }
2929
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002930 evlist__for_each(session->evlist, evsel) {
2931 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2932 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2933 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2934 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2935 evsel->handler = trace__pgfault;
2936 }
2937
David Ahernbdc89662013-08-28 22:29:53 -06002938 err = parse_target_str(trace);
2939 if (err != 0)
2940 goto out;
2941
David Ahern6810fc92013-08-28 22:29:52 -06002942 setup_pager();
2943
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002944 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002945 if (err)
2946 pr_err("Failed to process events, error %d", err);
2947
David Ahernbf2575c2013-10-08 21:26:53 -06002948 else if (trace->summary)
2949 trace__fprintf_thread_summary(trace, trace->output);
2950
David Ahern6810fc92013-08-28 22:29:52 -06002951out:
2952 perf_session__delete(session);
2953
2954 return err;
2955}
2956
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002957static size_t trace__fprintf_threads_header(FILE *fp)
2958{
2959 size_t printed;
2960
Pekka Enberg99ff7152013-11-12 16:42:14 +02002961 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002962
2963 return printed;
2964}
2965
2966static size_t thread__dump_stats(struct thread_trace *ttrace,
2967 struct trace *trace, FILE *fp)
2968{
2969 struct stats *stats;
2970 size_t printed = 0;
2971 struct syscall *sc;
2972 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2973
2974 if (inode == NULL)
2975 return 0;
2976
2977 printed += fprintf(fp, "\n");
2978
Milian Wolff834fd462015-08-06 11:24:29 +02002979 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2980 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2981 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002982
David Ahernbf2575c2013-10-08 21:26:53 -06002983 /* each int_node is a syscall */
2984 while (inode) {
2985 stats = inode->priv;
2986 if (stats) {
2987 double min = (double)(stats->min) / NSEC_PER_MSEC;
2988 double max = (double)(stats->max) / NSEC_PER_MSEC;
2989 double avg = avg_stats(stats);
2990 double pct;
2991 u64 n = (u64) stats->n;
2992
2993 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2994 avg /= NSEC_PER_MSEC;
2995
2996 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002997 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002998 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
2999 n, avg * n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02003000 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06003001 }
3002
3003 inode = intlist__next(inode);
3004 }
3005
3006 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003007
3008 return printed;
3009}
3010
David Ahern896cbb52013-09-28 13:12:59 -06003011/* struct used to pass data to per-thread function */
3012struct summary_data {
3013 FILE *fp;
3014 struct trace *trace;
3015 size_t printed;
3016};
3017
3018static int trace__fprintf_one_thread(struct thread *thread, void *priv)
3019{
3020 struct summary_data *data = priv;
3021 FILE *fp = data->fp;
3022 size_t printed = data->printed;
3023 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09003024 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06003025 double ratio;
3026
3027 if (ttrace == NULL)
3028 return 0;
3029
3030 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
3031
Pekka Enberg15e65c62013-11-14 18:43:30 +02003032 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003033 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02003034 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04003035 if (ttrace->pfmaj)
3036 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
3037 if (ttrace->pfmin)
3038 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003039 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06003040 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06003041
3042 data->printed += printed;
3043
3044 return 0;
3045}
3046
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003047static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
3048{
David Ahern896cbb52013-09-28 13:12:59 -06003049 struct summary_data data = {
3050 .fp = fp,
3051 .trace = trace
3052 };
3053 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003054
David Ahern896cbb52013-09-28 13:12:59 -06003055 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003056
David Ahern896cbb52013-09-28 13:12:59 -06003057 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003058}
3059
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003060static int trace__set_duration(const struct option *opt, const char *str,
3061 int unset __maybe_unused)
3062{
3063 struct trace *trace = opt->value;
3064
3065 trace->duration_filter = atof(str);
3066 return 0;
3067}
3068
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08003069static int trace__set_filter_pids(const struct option *opt, const char *str,
3070 int unset __maybe_unused)
3071{
3072 int ret = -1;
3073 size_t i;
3074 struct trace *trace = opt->value;
3075 /*
3076 * FIXME: introduce a intarray class, plain parse csv and create a
3077 * { int nr, int entries[] } struct...
3078 */
3079 struct intlist *list = intlist__new(str);
3080
3081 if (list == NULL)
3082 return -1;
3083
3084 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
3085 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
3086
3087 if (trace->filter_pids.entries == NULL)
3088 goto out;
3089
3090 trace->filter_pids.entries[0] = getpid();
3091
3092 for (i = 1; i < trace->filter_pids.nr; ++i)
3093 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
3094
3095 intlist__delete(list);
3096 ret = 0;
3097out:
3098 return ret;
3099}
3100
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003101static int trace__open_output(struct trace *trace, const char *filename)
3102{
3103 struct stat st;
3104
3105 if (!stat(filename, &st) && st.st_size) {
3106 char oldname[PATH_MAX];
3107
3108 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
3109 unlink(oldname);
3110 rename(filename, oldname);
3111 }
3112
3113 trace->output = fopen(filename, "w");
3114
3115 return trace->output == NULL ? -errno : 0;
3116}
3117
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003118static int parse_pagefaults(const struct option *opt, const char *str,
3119 int unset __maybe_unused)
3120{
3121 int *trace_pgfaults = opt->value;
3122
3123 if (strcmp(str, "all") == 0)
3124 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
3125 else if (strcmp(str, "maj") == 0)
3126 *trace_pgfaults |= TRACE_PFMAJ;
3127 else if (strcmp(str, "min") == 0)
3128 *trace_pgfaults |= TRACE_PFMIN;
3129 else
3130 return -1;
3131
3132 return 0;
3133}
3134
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003135static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3136{
3137 struct perf_evsel *evsel;
3138
3139 evlist__for_each(evlist, evsel)
3140 evsel->handler = handler;
3141}
3142
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003143int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3144{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003145 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003146 "perf trace [<options>] [<command>]",
3147 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003148 "perf trace record [<options>] [<command>]",
3149 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003150 NULL
3151 };
3152 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003153 .audit = {
3154 .machine = audit_detect_machine(),
3155 .open_id = audit_name_to_syscall("open", trace.audit.machine),
3156 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003157 .syscalls = {
3158 . max = -1,
3159 },
3160 .opts = {
3161 .target = {
3162 .uid = UINT_MAX,
3163 .uses_mmap = true,
3164 },
3165 .user_freq = UINT_MAX,
3166 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003167 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003168 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003169 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003170 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003171 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003172 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003173 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003174 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003175 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003176 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003177 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003178 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3179 "event selector. use 'perf list' to list available events",
3180 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003181 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3182 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003183 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03003184 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003185 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003186 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003187 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3188 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003189 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003190 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003191 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3192 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003193 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003194 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003195 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003196 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003197 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003198 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003199 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3200 "number of mmap data pages",
3201 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003202 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003203 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003204 OPT_CALLBACK(0, "duration", &trace, "float",
3205 "show only events with duration > N.M ms",
3206 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003207 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003208 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003209 OPT_BOOLEAN('T', "time", &trace.full_time,
3210 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003211 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3212 "Show only syscall summary with statistics"),
3213 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3214 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003215 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3216 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003217 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003218 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003219 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3220 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003221 OPT_END()
3222 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003223 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003224 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003225 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003226
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003227 signal(SIGSEGV, sighandler_dump_stack);
3228 signal(SIGFPE, sighandler_dump_stack);
3229
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003230 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003231
3232 if (trace.evlist == NULL) {
3233 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003234 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003235 goto out;
3236 }
3237
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003238 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3239 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003240
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003241 if (trace.trace_pgfaults) {
3242 trace.opts.sample_address = true;
3243 trace.opts.sample_time = true;
3244 }
3245
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003246 if (trace.evlist->nr_entries > 0)
3247 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3248
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003249 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3250 return trace__record(&trace, argc-1, &argv[1]);
3251
3252 /* summary_only implies summary option, but don't overwrite summary if set */
3253 if (trace.summary_only)
3254 trace.summary = trace.summary_only;
3255
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003256 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3257 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003258 pr_err("Please specify something to trace.\n");
3259 return -1;
3260 }
3261
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003262 if (output_name != NULL) {
3263 err = trace__open_output(&trace, output_name);
3264 if (err < 0) {
3265 perror("failed to create output file");
3266 goto out;
3267 }
3268 }
3269
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003270 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003271 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003272 struct strlist_config slist_config = {
3273 .dirname = system_path(STRACE_GROUPS_DIR),
3274 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003275
3276 trace.not_ev_qualifier = *s == '!';
3277 if (trace.not_ev_qualifier)
3278 ++s;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003279 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003280 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003281 fputs("Not enough memory to parse event qualifier",
3282 trace.output);
3283 err = -ENOMEM;
3284 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003285 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003286
3287 err = trace__validate_ev_qualifier(&trace);
3288 if (err)
3289 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003290 }
3291
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003292 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003293 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003294 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003295 fprintf(trace.output, "%s", bf);
3296 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003297 }
3298
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003299 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003300 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003301 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003302 fprintf(trace.output, "%s", bf);
3303 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003304 }
3305
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003306 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003307 trace.opts.target.system_wide = true;
3308
David Ahern6810fc92013-08-28 22:29:52 -06003309 if (input_name)
3310 err = trace__replay(&trace);
3311 else
3312 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003313
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003314out_close:
3315 if (output_name != NULL)
3316 fclose(trace.output);
3317out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003318 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003319}