blob: 9a6c7b1fd5a156a16840a4d61aea4f0642ecf824 [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 Meloa3bca912016-04-06 12:51:33 -03001076#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001077#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001078
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001079static struct syscall_fmt {
1080 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001081 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001082 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001083 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001084 bool errmsg;
1085 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001086 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001087} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -03001088 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001089 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1090 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001091 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -03001092 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001093 { .name = "brk", .hexret = true,
1094 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001095 { .name = "chdir", .errmsg = true,
1096 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1097 { .name = "chmod", .errmsg = true,
1098 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1099 { .name = "chroot", .errmsg = true,
1100 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -06001101 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001102 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001103 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -03001104 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001105 { .name = "creat", .errmsg = true,
1106 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001107 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001108 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001109 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001110 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001111 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001112 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001113 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -03001114 { .name = "eventfd2", .errmsg = true,
1115 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001116 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001117 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1118 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001119 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001120 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001121 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001122 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001123 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001124 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001125 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001126 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001127 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001128 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1129 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001130 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001131 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001132 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001133 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1134 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001135 { .name = "fcntl", .errmsg = true,
1136 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1137 [1] = SCA_STRARRAY, /* cmd */ },
1138 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1139 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001140 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -03001141 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001142 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1143 [1] = SCA_FLOCK, /* cmd */ }, },
1144 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001145 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001146 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001147 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001148 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001149 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1150 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001151 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001152 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001153 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001154 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001155 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001156 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -03001157 { .name = "futex", .errmsg = true,
1158 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001159 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001160 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1161 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001162 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001163 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001164 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001165 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001166 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -03001167 { .name = "getrandom", .errmsg = true,
1168 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001169 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001170 { .name = "getxattr", .errmsg = true,
1171 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1172 { .name = "inotify_add_watch", .errmsg = true,
1173 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001174 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001175 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001176#if defined(__i386__) || defined(__x86_64__)
1177/*
1178 * FIXME: Make this available to all arches.
1179 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001180 [1] = SCA_STRHEXARRAY, /* cmd */
1181 [2] = SCA_HEX, /* arg */ },
1182 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001183#else
1184 [2] = SCA_HEX, /* arg */ }, },
1185#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -03001186 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001187 { .name = "kill", .errmsg = true,
1188 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001189 { .name = "lchown", .errmsg = true,
1190 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1191 { .name = "lgetxattr", .errmsg = true,
1192 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001193 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001194 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001195 { .name = "listxattr", .errmsg = true,
1196 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001197 { .name = "llistxattr", .errmsg = true,
1198 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1199 { .name = "lremovexattr", .errmsg = true,
1200 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001201 { .name = "lseek", .errmsg = true,
1202 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1203 [2] = SCA_STRARRAY, /* whence */ },
1204 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001205 { .name = "lsetxattr", .errmsg = true,
1206 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001207 { .name = "lstat", .errmsg = true, .alias = "newlstat",
1208 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001209 { .name = "lsxattr", .errmsg = true,
1210 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001211 { .name = "madvise", .errmsg = true,
1212 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1213 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001214 { .name = "mkdir", .errmsg = true,
1215 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001216 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001217 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1218 [1] = SCA_FILENAME, /* pathname */ }, },
1219 { .name = "mknod", .errmsg = true,
1220 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001221 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001222 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1223 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001224 { .name = "mlock", .errmsg = true,
1225 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1226 { .name = "mlockall", .errmsg = true,
1227 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001228 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001229 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001230 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001231 [3] = SCA_MMAP_FLAGS, /* flags */
1232 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001233 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001234 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1235 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001236 { .name = "mq_unlink", .errmsg = true,
1237 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001238 { .name = "mremap", .hexret = true,
1239 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001240 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001241 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001242 { .name = "munlock", .errmsg = true,
1243 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001244 { .name = "munmap", .errmsg = true,
1245 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001246 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001247 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001248 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001249 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1250 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001251 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001252 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1253 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001254 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001255 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1256 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001257 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001258 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001259 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001260 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001261 { .name = "perf_event_open", .errmsg = true,
1262 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1263 [2] = SCA_INT, /* cpu */
1264 [3] = SCA_FD, /* group_fd */
1265 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001266 { .name = "pipe2", .errmsg = true,
1267 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001268 { .name = "poll", .errmsg = true, .timeout = true, },
1269 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001270 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001271 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001272 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001273 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001274 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001275 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001276 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001277 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001278 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001279 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001280 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001281 { .name = "readlink", .errmsg = true,
1282 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001283 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001284 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1285 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001286 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001287 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001288 { .name = "recvfrom", .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 = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001292 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1293 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001294 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001295 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1296 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001297 { .name = "removexattr", .errmsg = true,
1298 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001299 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001300 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001301 { .name = "rmdir", .errmsg = true,
1302 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001303 { .name = "rt_sigaction", .errmsg = true,
1304 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001305 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001306 { .name = "rt_sigqueueinfo", .errmsg = true,
1307 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1308 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1309 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001310 { .name = "sched_setscheduler", .errmsg = true,
1311 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001312 { .name = "seccomp", .errmsg = true,
1313 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
1314 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001315 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001316 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001317 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1318 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001319 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001320 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1321 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001322 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001323 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1324 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001325 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1326 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001327 { .name = "setxattr", .errmsg = true,
1328 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001329 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001330 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001331 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001332 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1333 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001334 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001335 { .name = "socketpair", .errmsg = true,
1336 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1337 [1] = SCA_SK_TYPE, /* type */ },
1338 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001339 { .name = "stat", .errmsg = true, .alias = "newstat",
1340 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001341 { .name = "statfs", .errmsg = true,
1342 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1343 { .name = "swapoff", .errmsg = true,
1344 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1345 { .name = "swapon", .errmsg = true,
1346 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001347 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001348 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001349 { .name = "tgkill", .errmsg = true,
1350 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1351 { .name = "tkill", .errmsg = true,
1352 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001353 { .name = "truncate", .errmsg = true,
1354 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001355 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001356 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001357 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1358 [1] = SCA_FILENAME, /* pathname */ }, },
1359 { .name = "utime", .errmsg = true,
1360 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001361 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001362 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1363 [1] = SCA_FILENAME, /* filename */ }, },
1364 { .name = "utimes", .errmsg = true,
1365 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001366 { .name = "vmsplice", .errmsg = true,
1367 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001368 { .name = "wait4", .errmsg = true,
1369 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
1370 { .name = "waitid", .errmsg = true,
1371 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001372 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001373 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001374 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001375 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001376};
1377
1378static int syscall_fmt__cmp(const void *name, const void *fmtp)
1379{
1380 const struct syscall_fmt *fmt = fmtp;
1381 return strcmp(name, fmt->name);
1382}
1383
1384static struct syscall_fmt *syscall_fmt__find(const char *name)
1385{
1386 const int nmemb = ARRAY_SIZE(syscall_fmts);
1387 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1388}
1389
1390struct syscall {
1391 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001392 int nr_args;
1393 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001394 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001395 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001396 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001397 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001398 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001399};
1400
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001401static size_t fprintf_duration(unsigned long t, FILE *fp)
1402{
1403 double duration = (double)t / NSEC_PER_MSEC;
1404 size_t printed = fprintf(fp, "(");
1405
1406 if (duration >= 1.0)
1407 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1408 else if (duration >= 0.01)
1409 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1410 else
1411 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001412 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001413}
1414
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001415/**
1416 * filename.ptr: The filename char pointer that will be vfs_getname'd
1417 * filename.entry_str_pos: Where to insert the string translated from
1418 * filename.ptr by the vfs_getname tracepoint/kprobe.
1419 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001420struct thread_trace {
1421 u64 entry_time;
1422 u64 exit_time;
1423 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001424 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001425 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001426 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001427 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001428 struct {
1429 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001430 short int entry_str_pos;
1431 bool pending_open;
1432 unsigned int namelen;
1433 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001434 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001435 struct {
1436 int max;
1437 char **table;
1438 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001439
1440 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001441};
1442
1443static struct thread_trace *thread_trace__new(void)
1444{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001445 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1446
1447 if (ttrace)
1448 ttrace->paths.max = -1;
1449
David Ahernbf2575c2013-10-08 21:26:53 -06001450 ttrace->syscall_stats = intlist__new(NULL);
1451
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001452 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001453}
1454
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001455static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001456{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001457 struct thread_trace *ttrace;
1458
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001459 if (thread == NULL)
1460 goto fail;
1461
Namhyung Kim89dceb22014-10-06 09:46:03 +09001462 if (thread__priv(thread) == NULL)
1463 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001464
Namhyung Kim89dceb22014-10-06 09:46:03 +09001465 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001466 goto fail;
1467
Namhyung Kim89dceb22014-10-06 09:46:03 +09001468 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001469 ++ttrace->nr_events;
1470
1471 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001472fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001473 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001474 "WARNING: not enough memory, dropping samples!\n");
1475 return NULL;
1476}
1477
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001478#define TRACE_PFMAJ (1 << 0)
1479#define TRACE_PFMIN (1 << 1)
1480
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001481static const size_t trace__entry_str_size = 2048;
1482
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001483struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001484 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001485 struct {
1486 int machine;
1487 int open_id;
1488 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001489 struct {
1490 int max;
1491 struct syscall *table;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001492 struct {
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001493 struct perf_evsel *sys_enter,
1494 *sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001495 } events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001496 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001497 struct record_opts opts;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001498 struct perf_evlist *evlist;
David Ahern8fb598e2013-09-28 13:13:00 -06001499 struct machine *host;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001500 struct thread *current;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001501 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001502 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001503 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001504 struct strlist *ev_qualifier;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001505 struct {
1506 size_t nr;
1507 int *entries;
1508 } ev_qualifier_ids;
David Ahernbdc89662013-08-28 22:29:53 -06001509 struct intlist *tid_list;
1510 struct intlist *pid_list;
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08001511 struct {
1512 size_t nr;
1513 pid_t *entries;
1514 } filter_pids;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001515 double duration_filter;
1516 double runtime_ms;
1517 struct {
1518 u64 vfs_getname,
1519 proc_getname;
1520 } stats;
1521 bool not_ev_qualifier;
1522 bool live;
1523 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001524 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001525 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001526 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001527 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001528 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001529 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001530 bool trace_syscalls;
Yunlong Songe366a6d2015-04-02 21:47:18 +08001531 bool force;
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03001532 bool vfs_getname;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001533 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001534};
1535
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001536static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001537{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001538 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001539
1540 if (fd > ttrace->paths.max) {
1541 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1542
1543 if (npath == NULL)
1544 return -1;
1545
1546 if (ttrace->paths.max != -1) {
1547 memset(npath + ttrace->paths.max + 1, 0,
1548 (fd - ttrace->paths.max) * sizeof(char *));
1549 } else {
1550 memset(npath, 0, (fd + 1) * sizeof(char *));
1551 }
1552
1553 ttrace->paths.table = npath;
1554 ttrace->paths.max = fd;
1555 }
1556
1557 ttrace->paths.table[fd] = strdup(pathname);
1558
1559 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1560}
1561
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001562static int thread__read_fd_path(struct thread *thread, int fd)
1563{
1564 char linkname[PATH_MAX], pathname[PATH_MAX];
1565 struct stat st;
1566 int ret;
1567
1568 if (thread->pid_ == thread->tid) {
1569 scnprintf(linkname, sizeof(linkname),
1570 "/proc/%d/fd/%d", thread->pid_, fd);
1571 } else {
1572 scnprintf(linkname, sizeof(linkname),
1573 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1574 }
1575
1576 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1577 return -1;
1578
1579 ret = readlink(linkname, pathname, sizeof(pathname));
1580
1581 if (ret < 0 || ret > st.st_size)
1582 return -1;
1583
1584 pathname[ret] = '\0';
1585 return trace__set_fd_pathname(thread, fd, pathname);
1586}
1587
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001588static const char *thread__fd_path(struct thread *thread, int fd,
1589 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001590{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001591 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001592
1593 if (ttrace == NULL)
1594 return NULL;
1595
1596 if (fd < 0)
1597 return NULL;
1598
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001599 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001600 if (!trace->live)
1601 return NULL;
1602 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001603 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001604 return NULL;
1605 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001606
1607 return ttrace->paths.table[fd];
1608}
1609
1610static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1611 struct syscall_arg *arg)
1612{
1613 int fd = arg->val;
1614 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001615 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001616
1617 if (path)
1618 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1619
1620 return printed;
1621}
1622
1623static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1624 struct syscall_arg *arg)
1625{
1626 int fd = arg->val;
1627 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001628 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001629
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001630 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1631 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001632
1633 return printed;
1634}
1635
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001636static void thread__set_filename_pos(struct thread *thread, const char *bf,
1637 unsigned long ptr)
1638{
1639 struct thread_trace *ttrace = thread__priv(thread);
1640
1641 ttrace->filename.ptr = ptr;
1642 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1643}
1644
1645static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1646 struct syscall_arg *arg)
1647{
1648 unsigned long ptr = arg->val;
1649
1650 if (!arg->trace->vfs_getname)
1651 return scnprintf(bf, size, "%#x", ptr);
1652
1653 thread__set_filename_pos(arg->thread, bf, ptr);
1654 return 0;
1655}
1656
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001657static bool trace__filter_duration(struct trace *trace, double t)
1658{
1659 return t < (trace->duration_filter * NSEC_PER_MSEC);
1660}
1661
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001662static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1663{
1664 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1665
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001666 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001667}
1668
Namhyung Kimf15eb532012-10-05 14:02:16 +09001669static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001670static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001671
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001672static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001673{
1674 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001675 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001676}
1677
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001678static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001679 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001680{
1681 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001682 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001683
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001684 if (trace->multiple_threads) {
1685 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001686 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001687 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001688 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001689
1690 return printed;
1691}
1692
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001693static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001694 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001695{
1696 int ret = 0;
1697
1698 switch (event->header.type) {
1699 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001700 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001701 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001702 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001703 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001704 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001705 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001706 break;
1707 }
1708
1709 return ret;
1710}
1711
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001712static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001713 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001714 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001715 struct machine *machine)
1716{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001717 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001718 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001719}
1720
1721static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1722{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001723 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001724
1725 if (err)
1726 return err;
1727
David Ahern8fb598e2013-09-28 13:13:00 -06001728 trace->host = machine__new_host();
1729 if (trace->host == NULL)
1730 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001731
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001732 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001733 return -errno;
1734
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001735 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001736 evlist->threads, trace__tool_process, false,
1737 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001738 if (err)
1739 symbol__exit();
1740
1741 return err;
1742}
1743
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001744static int syscall__set_arg_fmts(struct syscall *sc)
1745{
1746 struct format_field *field;
1747 int idx = 0;
1748
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001749 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001750 if (sc->arg_scnprintf == NULL)
1751 return -1;
1752
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001753 if (sc->fmt)
1754 sc->arg_parm = sc->fmt->arg_parm;
1755
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001756 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001757 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1758 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1759 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001760 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1761 ++idx;
1762 }
1763
1764 return 0;
1765}
1766
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001767static int trace__read_syscall_info(struct trace *trace, int id)
1768{
1769 char tp_name[128];
1770 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001771 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001772
1773 if (name == NULL)
1774 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001775
1776 if (id > trace->syscalls.max) {
1777 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1778
1779 if (nsyscalls == NULL)
1780 return -1;
1781
1782 if (trace->syscalls.max != -1) {
1783 memset(nsyscalls + trace->syscalls.max + 1, 0,
1784 (id - trace->syscalls.max) * sizeof(*sc));
1785 } else {
1786 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1787 }
1788
1789 trace->syscalls.table = nsyscalls;
1790 trace->syscalls.max = id;
1791 }
1792
1793 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001794 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001795
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001796 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001797
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001798 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001799 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001800
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001801 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001802 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001803 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001804 }
1805
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001806 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001807 return -1;
1808
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001809 sc->args = sc->tp_format->format.fields;
1810 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001811 /*
1812 * We need to check and discard the first variable '__syscall_nr'
1813 * or 'nr' that mean the syscall number. It is needless here.
1814 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1815 */
1816 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001817 sc->args = sc->args->next;
1818 --sc->nr_args;
1819 }
1820
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001821 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1822
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001823 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001824}
1825
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001826static int trace__validate_ev_qualifier(struct trace *trace)
1827{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001828 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001829 struct str_node *pos;
1830
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001831 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1832 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1833 sizeof(trace->ev_qualifier_ids.entries[0]));
1834
1835 if (trace->ev_qualifier_ids.entries == NULL) {
1836 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1837 trace->output);
1838 err = -EINVAL;
1839 goto out;
1840 }
1841
1842 i = 0;
1843
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001844 strlist__for_each(pos, trace->ev_qualifier) {
1845 const char *sc = pos->s;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001846 int id = audit_name_to_syscall(sc, trace->audit.machine);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001847
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001848 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001849 if (err == 0) {
1850 fputs("Error:\tInvalid syscall ", trace->output);
1851 err = -EINVAL;
1852 } else {
1853 fputs(", ", trace->output);
1854 }
1855
1856 fputs(sc, trace->output);
1857 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001858
1859 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001860 }
1861
1862 if (err < 0) {
1863 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1864 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001865 zfree(&trace->ev_qualifier_ids.entries);
1866 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001867 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001868out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001869 return err;
1870}
1871
David Ahern55d43bc2015-02-19 15:00:22 -05001872/*
1873 * args is to be interpreted as a series of longs but we need to handle
1874 * 8-byte unaligned accesses. args points to raw_data within the event
1875 * and raw_data is guaranteed to be 8-byte unaligned because it is
1876 * preceded by raw_size which is a u32. So we need to copy args to a temp
1877 * variable to read it. Most notably this avoids extended load instructions
1878 * on unaligned addresses
1879 */
1880
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001881static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001882 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001883 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001884{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001885 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001886 unsigned char *p;
1887 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001888
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001889 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001890 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001891 u8 bit = 1;
1892 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001893 .idx = 0,
1894 .mask = 0,
1895 .trace = trace,
1896 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001897 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001898
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001899 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001900 field = field->next, ++arg.idx, bit <<= 1) {
1901 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001902 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001903
1904 /* special care for unaligned accesses */
1905 p = args + sizeof(unsigned long) * arg.idx;
1906 memcpy(&val, p, sizeof(val));
1907
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001908 /*
1909 * Suppress this argument if its value is zero and
1910 * and we don't have a string associated in an
1911 * strarray for it.
1912 */
David Ahern55d43bc2015-02-19 15:00:22 -05001913 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001914 !(sc->arg_scnprintf &&
1915 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1916 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001917 continue;
1918
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001919 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001920 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001921 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001922 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001923 if (sc->arg_parm)
1924 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001925 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1926 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001927 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001928 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001929 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001930 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001931 }
1932 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001933 int i = 0;
1934
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001935 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001936 /* special care for unaligned accesses */
1937 p = args + sizeof(unsigned long) * i;
1938 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001939 printed += scnprintf(bf + printed, size - printed,
1940 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001941 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001942 ++i;
1943 }
1944 }
1945
1946 return printed;
1947}
1948
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001949typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001950 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001951 struct perf_sample *sample);
1952
1953static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001954 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001955{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001956
1957 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001958
1959 /*
1960 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1961 * before that, leaving at a higher verbosity level till that is
1962 * explained. Reproduced with plain ftrace with:
1963 *
1964 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1965 * grep "NR -1 " /t/trace_pipe
1966 *
1967 * After generating some load on the machine.
1968 */
1969 if (verbose > 1) {
1970 static u64 n;
1971 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1972 id, perf_evsel__name(evsel), ++n);
1973 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001974 return NULL;
1975 }
1976
1977 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1978 trace__read_syscall_info(trace, id))
1979 goto out_cant_read;
1980
1981 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1982 goto out_cant_read;
1983
1984 return &trace->syscalls.table[id];
1985
1986out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001987 if (verbose) {
1988 fprintf(trace->output, "Problems reading syscall %d", id);
1989 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1990 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1991 fputs(" information\n", trace->output);
1992 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001993 return NULL;
1994}
1995
David Ahernbf2575c2013-10-08 21:26:53 -06001996static void thread__update_stats(struct thread_trace *ttrace,
1997 int id, struct perf_sample *sample)
1998{
1999 struct int_node *inode;
2000 struct stats *stats;
2001 u64 duration = 0;
2002
2003 inode = intlist__findnew(ttrace->syscall_stats, id);
2004 if (inode == NULL)
2005 return;
2006
2007 stats = inode->priv;
2008 if (stats == NULL) {
2009 stats = malloc(sizeof(struct stats));
2010 if (stats == NULL)
2011 return;
2012 init_stats(stats);
2013 inode->priv = stats;
2014 }
2015
2016 if (ttrace->entry_time && sample->time > ttrace->entry_time)
2017 duration = sample->time - ttrace->entry_time;
2018
2019 update_stats(stats, duration);
2020}
2021
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03002022static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
2023{
2024 struct thread_trace *ttrace;
2025 u64 duration;
2026 size_t printed;
2027
2028 if (trace->current == NULL)
2029 return 0;
2030
2031 ttrace = thread__priv(trace->current);
2032
2033 if (!ttrace->entry_pending)
2034 return 0;
2035
2036 duration = sample->time - ttrace->entry_time;
2037
2038 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
2039 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
2040 ttrace->entry_pending = false;
2041
2042 return printed;
2043}
2044
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002045static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002046 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002047 struct perf_sample *sample)
2048{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002049 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002050 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002051 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002052 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002053 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002054 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002055 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002056
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002057 if (sc == NULL)
2058 return -1;
2059
David Ahern8fb598e2013-09-28 13:13:00 -06002060 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002061 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002062 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002063 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002064
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002065 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002066
2067 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002068 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002069 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002070 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002071 }
2072
David Ahern13f22a22015-03-19 12:23:03 -06002073 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03002074 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03002075
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002076 ttrace->entry_time = sample->time;
2077 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002078 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002079
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002080 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002081 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002082
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03002083 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07002084 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002085 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
2086 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002087 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002088 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002089 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002090 /* See trace__vfs_getname & trace__sys_exit */
2091 ttrace->filename.pending_open = false;
2092 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002093
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002094 if (trace->current != thread) {
2095 thread__put(trace->current);
2096 trace->current = thread__get(thread);
2097 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002098 err = 0;
2099out_put:
2100 thread__put(thread);
2101 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002102}
2103
2104static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002105 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002106 struct perf_sample *sample)
2107{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002108 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002109 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002110 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002111 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002112 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002113 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002114
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002115 if (sc == NULL)
2116 return -1;
2117
David Ahern8fb598e2013-09-28 13:13:00 -06002118 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002119 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002120 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002121 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002122
David Ahernbf2575c2013-10-08 21:26:53 -06002123 if (trace->summary)
2124 thread__update_stats(ttrace, id, sample);
2125
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002126 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002127
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002128 if (id == trace->audit.open_id && ret >= 0 && ttrace->filename.pending_open) {
2129 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
2130 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002131 ++trace->stats.vfs_getname;
2132 }
2133
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002134 ttrace->exit_time = sample->time;
2135
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002136 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002137 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002138 if (trace__filter_duration(trace, duration))
2139 goto out;
2140 } else if (trace->duration_filter)
2141 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002142
David Ahernfd2eaba2013-11-12 09:31:15 -07002143 if (trace->summary_only)
2144 goto out;
2145
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002146 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002147
2148 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002149 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002150 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002151 fprintf(trace->output, " ... [");
2152 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
2153 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002154 }
2155
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002156 if (sc->fmt == NULL) {
2157signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002158 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002159 } else if (ret < 0 && sc->fmt->errmsg) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00002160 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002161 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
2162 *e = audit_errno_to_name(-ret);
2163
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002164 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002165 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002166 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03002167 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002168 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002169 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002170 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002171
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002172 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002173out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002174 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002175 err = 0;
2176out_put:
2177 thread__put(thread);
2178 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002179}
2180
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002181static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002182 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002183 struct perf_sample *sample)
2184{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002185 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2186 struct thread_trace *ttrace;
2187 size_t filename_len, entry_str_len, to_move;
2188 ssize_t remaining_space;
2189 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002190 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002191
2192 if (!thread)
2193 goto out;
2194
2195 ttrace = thread__priv(thread);
2196 if (!ttrace)
2197 goto out;
2198
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002199 filename_len = strlen(filename);
2200
2201 if (ttrace->filename.namelen < filename_len) {
2202 char *f = realloc(ttrace->filename.name, filename_len + 1);
2203
2204 if (f == NULL)
2205 goto out;
2206
2207 ttrace->filename.namelen = filename_len;
2208 ttrace->filename.name = f;
2209 }
2210
2211 strcpy(ttrace->filename.name, filename);
2212 ttrace->filename.pending_open = true;
2213
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002214 if (!ttrace->filename.ptr)
2215 goto out;
2216
2217 entry_str_len = strlen(ttrace->entry_str);
2218 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2219 if (remaining_space <= 0)
2220 goto out;
2221
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002222 if (filename_len > (size_t)remaining_space) {
2223 filename += filename_len - remaining_space;
2224 filename_len = remaining_space;
2225 }
2226
2227 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2228 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2229 memmove(pos + filename_len, pos, to_move);
2230 memcpy(pos, filename, filename_len);
2231
2232 ttrace->filename.ptr = 0;
2233 ttrace->filename.entry_str_pos = 0;
2234out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002235 return 0;
2236}
2237
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002238static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002239 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002240 struct perf_sample *sample)
2241{
2242 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2243 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06002244 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03002245 sample->pid,
2246 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002247 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002248
2249 if (ttrace == NULL)
2250 goto out_dump;
2251
2252 ttrace->runtime_ms += runtime_ms;
2253 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002254 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002255 return 0;
2256
2257out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002258 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002259 evsel->name,
2260 perf_evsel__strval(evsel, sample, "comm"),
2261 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2262 runtime,
2263 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002264 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002265 return 0;
2266}
2267
Wang Nan1d6c9402016-02-26 09:31:55 +00002268static void bpf_output__printer(enum binary_printer_ops op,
2269 unsigned int val, void *extra)
2270{
2271 FILE *output = extra;
2272 unsigned char ch = (unsigned char)val;
2273
2274 switch (op) {
2275 case BINARY_PRINT_CHAR_DATA:
2276 fprintf(output, "%c", isprint(ch) ? ch : '.');
2277 break;
2278 case BINARY_PRINT_DATA_BEGIN:
2279 case BINARY_PRINT_LINE_BEGIN:
2280 case BINARY_PRINT_ADDR:
2281 case BINARY_PRINT_NUM_DATA:
2282 case BINARY_PRINT_NUM_PAD:
2283 case BINARY_PRINT_SEP:
2284 case BINARY_PRINT_CHAR_PAD:
2285 case BINARY_PRINT_LINE_END:
2286 case BINARY_PRINT_DATA_END:
2287 default:
2288 break;
2289 }
2290}
2291
2292static void bpf_output__fprintf(struct trace *trace,
2293 struct perf_sample *sample)
2294{
2295 print_binary(sample->raw_data, sample->raw_size, 8,
2296 bpf_output__printer, trace->output);
2297}
2298
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002299static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2300 union perf_event *event __maybe_unused,
2301 struct perf_sample *sample)
2302{
2303 trace__printf_interrupted_entry(trace, sample);
2304 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002305
2306 if (trace->trace_syscalls)
2307 fprintf(trace->output, "( ): ");
2308
2309 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002310
Wang Nan1d6c9402016-02-26 09:31:55 +00002311 if (perf_evsel__is_bpf_output(evsel)) {
2312 bpf_output__fprintf(trace, sample);
2313 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002314 event_format__fprintf(evsel->tp_format, sample->cpu,
2315 sample->raw_data, sample->raw_size,
2316 trace->output);
2317 }
2318
2319 fprintf(trace->output, ")\n");
2320 return 0;
2321}
2322
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002323static void print_location(FILE *f, struct perf_sample *sample,
2324 struct addr_location *al,
2325 bool print_dso, bool print_sym)
2326{
2327
2328 if ((verbose || print_dso) && al->map)
2329 fprintf(f, "%s@", al->map->dso->long_name);
2330
2331 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002332 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002333 al->addr - al->sym->start);
2334 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002335 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002336 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002337 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002338}
2339
2340static int trace__pgfault(struct trace *trace,
2341 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002342 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002343 struct perf_sample *sample)
2344{
2345 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002346 struct addr_location al;
2347 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002348 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002349 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002350
2351 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002352 ttrace = thread__trace(thread, trace->output);
2353 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002354 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002355
2356 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2357 ttrace->pfmaj++;
2358 else
2359 ttrace->pfmin++;
2360
2361 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002362 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002363
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002364 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002365 sample->ip, &al);
2366
2367 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2368
2369 fprintf(trace->output, "%sfault [",
2370 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2371 "maj" : "min");
2372
2373 print_location(trace->output, sample, &al, false, true);
2374
2375 fprintf(trace->output, "] => ");
2376
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002377 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002378 sample->addr, &al);
2379
2380 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002381 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002382 MAP__FUNCTION, sample->addr, &al);
2383
2384 if (al.map)
2385 map_type = 'x';
2386 else
2387 map_type = '?';
2388 }
2389
2390 print_location(trace->output, sample, &al, true, false);
2391
2392 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002393out:
2394 err = 0;
2395out_put:
2396 thread__put(thread);
2397 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002398}
2399
David Ahernbdc89662013-08-28 22:29:53 -06002400static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2401{
2402 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2403 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2404 return false;
2405
2406 if (trace->pid_list || trace->tid_list)
2407 return true;
2408
2409 return false;
2410}
2411
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002412static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002413 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002414 struct perf_sample *sample)
2415{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002416 /*
2417 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2418 * and don't use sample->time unconditionally, we may end up having
2419 * some other event in the future without PERF_SAMPLE_TIME for good
2420 * reason, i.e. we may not be interested in its timestamps, just in
2421 * it taking place, picking some piece of information when it
2422 * appears in our event stream (vfs_getname comes to mind).
2423 */
2424 if (trace->base_time == 0 && !trace->full_time &&
2425 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002426 trace->base_time = sample->time;
2427}
2428
David Ahern6810fc92013-08-28 22:29:52 -06002429static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002430 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002431 struct perf_sample *sample,
2432 struct perf_evsel *evsel,
2433 struct machine *machine __maybe_unused)
2434{
2435 struct trace *trace = container_of(tool, struct trace, tool);
2436 int err = 0;
2437
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002438 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002439
David Ahernbdc89662013-08-28 22:29:53 -06002440 if (skip_sample(trace, sample))
2441 return 0;
2442
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002443 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002444
David Ahern31605652013-12-04 19:41:41 -07002445 if (handler) {
2446 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002447 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002448 }
David Ahern6810fc92013-08-28 22:29:52 -06002449
2450 return err;
2451}
2452
David Ahernbdc89662013-08-28 22:29:53 -06002453static int parse_target_str(struct trace *trace)
2454{
2455 if (trace->opts.target.pid) {
2456 trace->pid_list = intlist__new(trace->opts.target.pid);
2457 if (trace->pid_list == NULL) {
2458 pr_err("Error parsing process id string\n");
2459 return -EINVAL;
2460 }
2461 }
2462
2463 if (trace->opts.target.tid) {
2464 trace->tid_list = intlist__new(trace->opts.target.tid);
2465 if (trace->tid_list == NULL) {
2466 pr_err("Error parsing thread id string\n");
2467 return -EINVAL;
2468 }
2469 }
2470
2471 return 0;
2472}
2473
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002474static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002475{
2476 unsigned int rec_argc, i, j;
2477 const char **rec_argv;
2478 const char * const record_args[] = {
2479 "record",
2480 "-R",
2481 "-m", "1024",
2482 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002483 };
2484
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002485 const char * const sc_args[] = { "-e", };
2486 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2487 const char * const majpf_args[] = { "-e", "major-faults" };
2488 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2489 const char * const minpf_args[] = { "-e", "minor-faults" };
2490 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2491
David Ahern9aca7f12013-12-04 19:41:39 -07002492 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002493 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2494 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002495 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2496
2497 if (rec_argv == NULL)
2498 return -ENOMEM;
2499
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002500 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002501 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002502 rec_argv[j++] = record_args[i];
2503
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002504 if (trace->trace_syscalls) {
2505 for (i = 0; i < sc_args_nr; i++)
2506 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002507
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002508 /* event string may be different for older kernels - e.g., RHEL6 */
2509 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2510 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2511 else if (is_valid_tracepoint("syscalls:sys_enter"))
2512 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2513 else {
2514 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2515 return -1;
2516 }
David Ahern9aca7f12013-12-04 19:41:39 -07002517 }
David Ahern9aca7f12013-12-04 19:41:39 -07002518
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002519 if (trace->trace_pgfaults & TRACE_PFMAJ)
2520 for (i = 0; i < majpf_args_nr; i++)
2521 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002522
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002523 if (trace->trace_pgfaults & TRACE_PFMIN)
2524 for (i = 0; i < minpf_args_nr; i++)
2525 rec_argv[j++] = minpf_args[i];
2526
2527 for (i = 0; i < (unsigned int)argc; i++)
2528 rec_argv[j++] = argv[i];
2529
2530 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002531}
2532
David Ahernbf2575c2013-10-08 21:26:53 -06002533static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2534
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002535static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002536{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002537 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002538
2539 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002540 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002541
2542 if (perf_evsel__field(evsel, "pathname") == NULL) {
2543 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002544 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002545 }
2546
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002547 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002548 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002549 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002550}
2551
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002552static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2553 u64 config)
2554{
2555 struct perf_evsel *evsel;
2556 struct perf_event_attr attr = {
2557 .type = PERF_TYPE_SOFTWARE,
2558 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002559 };
2560
2561 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002562 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002563
2564 event_attr_init(&attr);
2565
2566 evsel = perf_evsel__new(&attr);
2567 if (!evsel)
2568 return -ENOMEM;
2569
2570 evsel->handler = trace__pgfault;
2571 perf_evlist__add(evlist, evsel);
2572
2573 return 0;
2574}
2575
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002576static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2577{
2578 const u32 type = event->header.type;
2579 struct perf_evsel *evsel;
2580
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002581 if (type != PERF_RECORD_SAMPLE) {
2582 trace__process_event(trace, trace->host, event, sample);
2583 return;
2584 }
2585
2586 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2587 if (evsel == NULL) {
2588 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2589 return;
2590 }
2591
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002592 trace__set_base_time(trace, evsel, sample);
2593
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002594 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2595 sample->raw_data == NULL) {
2596 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2597 perf_evsel__name(evsel), sample->tid,
2598 sample->cpu, sample->raw_size);
2599 } else {
2600 tracepoint_handler handler = evsel->handler;
2601 handler(trace, evsel, event, sample);
2602 }
2603}
2604
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002605static int trace__add_syscall_newtp(struct trace *trace)
2606{
2607 int ret = -1;
2608 struct perf_evlist *evlist = trace->evlist;
2609 struct perf_evsel *sys_enter, *sys_exit;
2610
2611 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2612 if (sys_enter == NULL)
2613 goto out;
2614
2615 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2616 goto out_delete_sys_enter;
2617
2618 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2619 if (sys_exit == NULL)
2620 goto out_delete_sys_enter;
2621
2622 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2623 goto out_delete_sys_exit;
2624
2625 perf_evlist__add(evlist, sys_enter);
2626 perf_evlist__add(evlist, sys_exit);
2627
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002628 trace->syscalls.events.sys_enter = sys_enter;
2629 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002630
2631 ret = 0;
2632out:
2633 return ret;
2634
2635out_delete_sys_exit:
2636 perf_evsel__delete_priv(sys_exit);
2637out_delete_sys_enter:
2638 perf_evsel__delete_priv(sys_enter);
2639 goto out;
2640}
2641
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002642static int trace__set_ev_qualifier_filter(struct trace *trace)
2643{
2644 int err = -1;
2645 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2646 trace->ev_qualifier_ids.nr,
2647 trace->ev_qualifier_ids.entries);
2648
2649 if (filter == NULL)
2650 goto out_enomem;
2651
2652 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2653 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2654
2655 free(filter);
2656out:
2657 return err;
2658out_enomem:
2659 errno = ENOMEM;
2660 goto out;
2661}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002662
Namhyung Kimf15eb532012-10-05 14:02:16 +09002663static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002664{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002665 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002666 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002667 int err = -1, i;
2668 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002669 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002670 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002671
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002672 trace->live = true;
2673
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002674 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002675 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002676
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002677 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002678 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002679
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002680 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002681 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002682 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002683 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002684
2685 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2686 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002687 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002688
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002689 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002690 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2691 trace__sched_stat_runtime))
2692 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002693
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002694 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2695 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002696 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002697 goto out_delete_evlist;
2698 }
2699
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002700 err = trace__symbols_init(trace, evlist);
2701 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002702 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002703 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002704 }
2705
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002706 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002707
Namhyung Kimf15eb532012-10-05 14:02:16 +09002708 signal(SIGCHLD, sig_handler);
2709 signal(SIGINT, sig_handler);
2710
2711 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002712 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002713 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002714 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002715 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002716 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002717 }
2718 }
2719
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002720 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002721 if (err < 0)
2722 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002723
Wang Nanba504232016-02-26 09:31:54 +00002724 err = bpf__apply_obj_config();
2725 if (err) {
2726 char errbuf[BUFSIZ];
2727
2728 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2729 pr_err("ERROR: Apply config to BPF failed: %s\n",
2730 errbuf);
2731 goto out_error_open;
2732 }
2733
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002734 /*
2735 * Better not use !target__has_task() here because we need to cover the
2736 * case where no threads were specified in the command line, but a
2737 * workload was, and in that case we will fill in the thread_map when
2738 * we fork the workload in perf_evlist__prepare_workload.
2739 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002740 if (trace->filter_pids.nr > 0)
2741 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002742 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002743 err = perf_evlist__set_filter_pid(evlist, getpid());
2744
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002745 if (err < 0)
2746 goto out_error_mem;
2747
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002748 if (trace->ev_qualifier_ids.nr > 0) {
2749 err = trace__set_ev_qualifier_filter(trace);
2750 if (err < 0)
2751 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002752
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002753 pr_debug("event qualifier tracepoint filter: %s\n",
2754 trace->syscalls.events.sys_exit->filter);
2755 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002756
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002757 err = perf_evlist__apply_filters(evlist, &evsel);
2758 if (err < 0)
2759 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002760
Jiri Olsaf8850372013-11-28 17:57:22 +01002761 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002762 if (err < 0)
2763 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002764
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002765 if (!target__none(&trace->opts.target))
2766 perf_evlist__enable(evlist);
2767
Namhyung Kimf15eb532012-10-05 14:02:16 +09002768 if (forks)
2769 perf_evlist__start_workload(evlist);
2770
Jiri Olsae13798c2015-06-23 00:36:02 +02002771 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002772 evlist->threads->nr > 1 ||
2773 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002774again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002775 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002776
2777 for (i = 0; i < evlist->nr_mmaps; i++) {
2778 union perf_event *event;
2779
2780 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002781 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002782
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002783 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002784
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002785 err = perf_evlist__parse_sample(evlist, event, &sample);
2786 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002787 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002788 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002789 }
2790
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002791 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002792next_event:
2793 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002794
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002795 if (interrupted)
2796 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002797
2798 if (done && !draining) {
2799 perf_evlist__disable(evlist);
2800 draining = true;
2801 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002802 }
2803 }
2804
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002805 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002806 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002807
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002808 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2809 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2810 draining = true;
2811
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002812 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002813 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002814 } else {
2815 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002816 }
2817
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002818out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002819 thread__zput(trace->current);
2820
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002821 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002822
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002823 if (!err) {
2824 if (trace->summary)
2825 trace__fprintf_thread_summary(trace, trace->output);
2826
2827 if (trace->show_tool_stats) {
2828 fprintf(trace->output, "Stats:\n "
2829 " vfs_getname : %" PRIu64 "\n"
2830 " proc_getname: %" PRIu64 "\n",
2831 trace->stats.vfs_getname,
2832 trace->stats.proc_getname);
2833 }
2834 }
David Ahernbf2575c2013-10-08 21:26:53 -06002835
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002836out_delete_evlist:
2837 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002838 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002839 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002840 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002841{
2842 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002843
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002844out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002845 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002846 goto out_error;
2847
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002848out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002849 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002850 goto out_error;
2851
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002852out_error_mmap:
2853 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2854 goto out_error;
2855
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002856out_error_open:
2857 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2858
2859out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002860 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302861 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002862
2863out_error_apply_filters:
2864 fprintf(trace->output,
2865 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2866 evsel->filter, perf_evsel__name(evsel), errno,
2867 strerror_r(errno, errbuf, sizeof(errbuf)));
2868 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002869}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002870out_error_mem:
2871 fprintf(trace->output, "Not enough memory to run!\n");
2872 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002873
2874out_errno:
2875 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2876 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002877}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002878
David Ahern6810fc92013-08-28 22:29:52 -06002879static int trace__replay(struct trace *trace)
2880{
2881 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002882 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002883 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002884 struct perf_data_file file = {
2885 .path = input_name,
2886 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002887 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002888 };
David Ahern6810fc92013-08-28 22:29:52 -06002889 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002890 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002891 int err = -1;
2892
2893 trace->tool.sample = trace__process_sample;
2894 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002895 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002896 trace->tool.comm = perf_event__process_comm;
2897 trace->tool.exit = perf_event__process_exit;
2898 trace->tool.fork = perf_event__process_fork;
2899 trace->tool.attr = perf_event__process_attr;
2900 trace->tool.tracing_data = perf_event__process_tracing_data;
2901 trace->tool.build_id = perf_event__process_build_id;
2902
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002903 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002904 trace->tool.ordering_requires_timestamps = true;
2905
2906 /* add tid to output */
2907 trace->multiple_threads = true;
2908
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002909 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002910 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002911 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002912
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002913 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002914 goto out;
2915
David Ahern8fb598e2013-09-28 13:13:00 -06002916 trace->host = &session->machines.host;
2917
David Ahern6810fc92013-08-28 22:29:52 -06002918 err = perf_session__set_tracepoints_handlers(session, handlers);
2919 if (err)
2920 goto out;
2921
Namhyung Kim003824e2013-11-12 15:25:00 +09002922 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2923 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002924 /* older kernels have syscalls tp versus raw_syscalls */
2925 if (evsel == NULL)
2926 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2927 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002928
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002929 if (evsel &&
2930 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2931 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002932 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2933 goto out;
2934 }
2935
2936 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2937 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002938 if (evsel == NULL)
2939 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2940 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002941 if (evsel &&
2942 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2943 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002944 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002945 goto out;
2946 }
2947
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002948 evlist__for_each(session->evlist, evsel) {
2949 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2950 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2951 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2952 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2953 evsel->handler = trace__pgfault;
2954 }
2955
David Ahernbdc89662013-08-28 22:29:53 -06002956 err = parse_target_str(trace);
2957 if (err != 0)
2958 goto out;
2959
David Ahern6810fc92013-08-28 22:29:52 -06002960 setup_pager();
2961
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002962 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002963 if (err)
2964 pr_err("Failed to process events, error %d", err);
2965
David Ahernbf2575c2013-10-08 21:26:53 -06002966 else if (trace->summary)
2967 trace__fprintf_thread_summary(trace, trace->output);
2968
David Ahern6810fc92013-08-28 22:29:52 -06002969out:
2970 perf_session__delete(session);
2971
2972 return err;
2973}
2974
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002975static size_t trace__fprintf_threads_header(FILE *fp)
2976{
2977 size_t printed;
2978
Pekka Enberg99ff7152013-11-12 16:42:14 +02002979 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002980
2981 return printed;
2982}
2983
2984static size_t thread__dump_stats(struct thread_trace *ttrace,
2985 struct trace *trace, FILE *fp)
2986{
2987 struct stats *stats;
2988 size_t printed = 0;
2989 struct syscall *sc;
2990 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2991
2992 if (inode == NULL)
2993 return 0;
2994
2995 printed += fprintf(fp, "\n");
2996
Milian Wolff834fd462015-08-06 11:24:29 +02002997 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2998 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2999 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02003000
David Ahernbf2575c2013-10-08 21:26:53 -06003001 /* each int_node is a syscall */
3002 while (inode) {
3003 stats = inode->priv;
3004 if (stats) {
3005 double min = (double)(stats->min) / NSEC_PER_MSEC;
3006 double max = (double)(stats->max) / NSEC_PER_MSEC;
3007 double avg = avg_stats(stats);
3008 double pct;
3009 u64 n = (u64) stats->n;
3010
3011 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
3012 avg /= NSEC_PER_MSEC;
3013
3014 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02003015 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02003016 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
3017 n, avg * n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02003018 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06003019 }
3020
3021 inode = intlist__next(inode);
3022 }
3023
3024 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003025
3026 return printed;
3027}
3028
David Ahern896cbb52013-09-28 13:12:59 -06003029/* struct used to pass data to per-thread function */
3030struct summary_data {
3031 FILE *fp;
3032 struct trace *trace;
3033 size_t printed;
3034};
3035
3036static int trace__fprintf_one_thread(struct thread *thread, void *priv)
3037{
3038 struct summary_data *data = priv;
3039 FILE *fp = data->fp;
3040 size_t printed = data->printed;
3041 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09003042 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06003043 double ratio;
3044
3045 if (ttrace == NULL)
3046 return 0;
3047
3048 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
3049
Pekka Enberg15e65c62013-11-14 18:43:30 +02003050 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003051 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02003052 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04003053 if (ttrace->pfmaj)
3054 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
3055 if (ttrace->pfmin)
3056 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003057 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06003058 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06003059
3060 data->printed += printed;
3061
3062 return 0;
3063}
3064
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003065static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
3066{
David Ahern896cbb52013-09-28 13:12:59 -06003067 struct summary_data data = {
3068 .fp = fp,
3069 .trace = trace
3070 };
3071 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003072
David Ahern896cbb52013-09-28 13:12:59 -06003073 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003074
David Ahern896cbb52013-09-28 13:12:59 -06003075 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003076}
3077
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003078static int trace__set_duration(const struct option *opt, const char *str,
3079 int unset __maybe_unused)
3080{
3081 struct trace *trace = opt->value;
3082
3083 trace->duration_filter = atof(str);
3084 return 0;
3085}
3086
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08003087static int trace__set_filter_pids(const struct option *opt, const char *str,
3088 int unset __maybe_unused)
3089{
3090 int ret = -1;
3091 size_t i;
3092 struct trace *trace = opt->value;
3093 /*
3094 * FIXME: introduce a intarray class, plain parse csv and create a
3095 * { int nr, int entries[] } struct...
3096 */
3097 struct intlist *list = intlist__new(str);
3098
3099 if (list == NULL)
3100 return -1;
3101
3102 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
3103 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
3104
3105 if (trace->filter_pids.entries == NULL)
3106 goto out;
3107
3108 trace->filter_pids.entries[0] = getpid();
3109
3110 for (i = 1; i < trace->filter_pids.nr; ++i)
3111 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
3112
3113 intlist__delete(list);
3114 ret = 0;
3115out:
3116 return ret;
3117}
3118
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003119static int trace__open_output(struct trace *trace, const char *filename)
3120{
3121 struct stat st;
3122
3123 if (!stat(filename, &st) && st.st_size) {
3124 char oldname[PATH_MAX];
3125
3126 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
3127 unlink(oldname);
3128 rename(filename, oldname);
3129 }
3130
3131 trace->output = fopen(filename, "w");
3132
3133 return trace->output == NULL ? -errno : 0;
3134}
3135
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003136static int parse_pagefaults(const struct option *opt, const char *str,
3137 int unset __maybe_unused)
3138{
3139 int *trace_pgfaults = opt->value;
3140
3141 if (strcmp(str, "all") == 0)
3142 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
3143 else if (strcmp(str, "maj") == 0)
3144 *trace_pgfaults |= TRACE_PFMAJ;
3145 else if (strcmp(str, "min") == 0)
3146 *trace_pgfaults |= TRACE_PFMIN;
3147 else
3148 return -1;
3149
3150 return 0;
3151}
3152
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003153static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3154{
3155 struct perf_evsel *evsel;
3156
3157 evlist__for_each(evlist, evsel)
3158 evsel->handler = handler;
3159}
3160
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003161int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3162{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003163 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003164 "perf trace [<options>] [<command>]",
3165 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003166 "perf trace record [<options>] [<command>]",
3167 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003168 NULL
3169 };
3170 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003171 .audit = {
3172 .machine = audit_detect_machine(),
3173 .open_id = audit_name_to_syscall("open", trace.audit.machine),
3174 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003175 .syscalls = {
3176 . max = -1,
3177 },
3178 .opts = {
3179 .target = {
3180 .uid = UINT_MAX,
3181 .uses_mmap = true,
3182 },
3183 .user_freq = UINT_MAX,
3184 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003185 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003186 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003187 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003188 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003189 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003190 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003191 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003192 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003193 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003194 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003195 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003196 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3197 "event selector. use 'perf list' to list available events",
3198 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003199 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3200 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003201 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03003202 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003203 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003204 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003205 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3206 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003207 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003208 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003209 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3210 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003211 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003212 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003213 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003214 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003215 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003216 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003217 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3218 "number of mmap data pages",
3219 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003220 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003221 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003222 OPT_CALLBACK(0, "duration", &trace, "float",
3223 "show only events with duration > N.M ms",
3224 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003225 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003226 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003227 OPT_BOOLEAN('T', "time", &trace.full_time,
3228 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003229 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3230 "Show only syscall summary with statistics"),
3231 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3232 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003233 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3234 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003235 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003236 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003237 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3238 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003239 OPT_END()
3240 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003241 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003242 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003243 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003244
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003245 signal(SIGSEGV, sighandler_dump_stack);
3246 signal(SIGFPE, sighandler_dump_stack);
3247
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003248 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003249
3250 if (trace.evlist == NULL) {
3251 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003252 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003253 goto out;
3254 }
3255
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003256 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3257 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003258
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003259 if (trace.trace_pgfaults) {
3260 trace.opts.sample_address = true;
3261 trace.opts.sample_time = true;
3262 }
3263
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003264 if (trace.evlist->nr_entries > 0)
3265 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3266
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003267 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3268 return trace__record(&trace, argc-1, &argv[1]);
3269
3270 /* summary_only implies summary option, but don't overwrite summary if set */
3271 if (trace.summary_only)
3272 trace.summary = trace.summary_only;
3273
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003274 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3275 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003276 pr_err("Please specify something to trace.\n");
3277 return -1;
3278 }
3279
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003280 if (output_name != NULL) {
3281 err = trace__open_output(&trace, output_name);
3282 if (err < 0) {
3283 perror("failed to create output file");
3284 goto out;
3285 }
3286 }
3287
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003288 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003289 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003290 struct strlist_config slist_config = {
3291 .dirname = system_path(STRACE_GROUPS_DIR),
3292 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003293
3294 trace.not_ev_qualifier = *s == '!';
3295 if (trace.not_ev_qualifier)
3296 ++s;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003297 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003298 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003299 fputs("Not enough memory to parse event qualifier",
3300 trace.output);
3301 err = -ENOMEM;
3302 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003303 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003304
3305 err = trace__validate_ev_qualifier(&trace);
3306 if (err)
3307 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003308 }
3309
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003310 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003311 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003312 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003313 fprintf(trace.output, "%s", bf);
3314 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003315 }
3316
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003317 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003318 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003319 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003320 fprintf(trace.output, "%s", bf);
3321 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003322 }
3323
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003324 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003325 trace.opts.target.system_wide = true;
3326
David Ahern6810fc92013-08-28 22:29:52 -06003327 if (input_name)
3328 err = trace__replay(&trace);
3329 else
3330 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003331
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003332out_close:
3333 if (output_name != NULL)
3334 fclose(trace.output);
3335out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003336 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003337}