blob: 191f4d61eb161f0666675e9200ea8a741ce0abf7 [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;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001085 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001086 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001087 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001088} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -03001089 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001090 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1091 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001092 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -03001093 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001094 { .name = "brk", .hexret = true,
1095 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001096 { .name = "chdir", .errmsg = true,
1097 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1098 { .name = "chmod", .errmsg = true,
1099 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1100 { .name = "chroot", .errmsg = true,
1101 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -06001102 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001103 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001104 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001105 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -03001106 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001107 { .name = "creat", .errmsg = true,
1108 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001109 { .name = "dup", .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 = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001112 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001113 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001114 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001115 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -03001116 { .name = "eventfd2", .errmsg = true,
1117 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001118 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001119 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1120 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001121 { .name = "fadvise64", .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 = "fallocate", .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 = "fchdir", .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 = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001128 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001129 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001130 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1131 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001132 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001133 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001134 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001135 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1136 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001137 { .name = "fcntl", .errmsg = true,
1138 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1139 [1] = SCA_STRARRAY, /* cmd */ },
1140 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1141 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001142 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -03001143 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001144 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1145 [1] = SCA_FLOCK, /* cmd */ }, },
1146 { .name = "fsetxattr", .errmsg = true,
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 = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001149 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001150 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001151 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1152 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001153 { .name = "fstatfs", .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 = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001156 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001157 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001158 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -03001159 { .name = "futex", .errmsg = true,
1160 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001161 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001162 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1163 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001164 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001165 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001166 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001167 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001168 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001169 { .name = "getpid", .errpid = true, },
1170 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -03001171 { .name = "getrandom", .errmsg = true,
1172 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001173 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001174 { .name = "getxattr", .errmsg = true,
1175 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1176 { .name = "inotify_add_watch", .errmsg = true,
1177 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001178 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001179 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001180#if defined(__i386__) || defined(__x86_64__)
1181/*
1182 * FIXME: Make this available to all arches.
1183 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001184 [1] = SCA_STRHEXARRAY, /* cmd */
1185 [2] = SCA_HEX, /* arg */ },
1186 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001187#else
1188 [2] = SCA_HEX, /* arg */ }, },
1189#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -03001190 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001191 { .name = "kill", .errmsg = true,
1192 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001193 { .name = "lchown", .errmsg = true,
1194 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1195 { .name = "lgetxattr", .errmsg = true,
1196 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001197 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001198 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001199 { .name = "listxattr", .errmsg = true,
1200 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001201 { .name = "llistxattr", .errmsg = true,
1202 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1203 { .name = "lremovexattr", .errmsg = true,
1204 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001205 { .name = "lseek", .errmsg = true,
1206 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1207 [2] = SCA_STRARRAY, /* whence */ },
1208 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001209 { .name = "lsetxattr", .errmsg = true,
1210 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001211 { .name = "lstat", .errmsg = true, .alias = "newlstat",
1212 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001213 { .name = "lsxattr", .errmsg = true,
1214 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001215 { .name = "madvise", .errmsg = true,
1216 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1217 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001218 { .name = "mkdir", .errmsg = true,
1219 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001220 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001221 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1222 [1] = SCA_FILENAME, /* pathname */ }, },
1223 { .name = "mknod", .errmsg = true,
1224 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001225 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001226 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1227 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001228 { .name = "mlock", .errmsg = true,
1229 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1230 { .name = "mlockall", .errmsg = true,
1231 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001232 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001233 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001234 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001235 [3] = SCA_MMAP_FLAGS, /* flags */
1236 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001237 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001238 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1239 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001240 { .name = "mq_unlink", .errmsg = true,
1241 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001242 { .name = "mremap", .hexret = true,
1243 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001244 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001245 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001246 { .name = "munlock", .errmsg = true,
1247 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001248 { .name = "munmap", .errmsg = true,
1249 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001250 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001251 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001252 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001253 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1254 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001255 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001256 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1257 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001258 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001259 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1260 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001261 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001262 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001263 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001264 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001265 { .name = "perf_event_open", .errmsg = true,
1266 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1267 [2] = SCA_INT, /* cpu */
1268 [3] = SCA_FD, /* group_fd */
1269 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001270 { .name = "pipe2", .errmsg = true,
1271 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001272 { .name = "poll", .errmsg = true, .timeout = true, },
1273 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001274 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001275 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001276 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001277 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001278 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001279 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001280 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001281 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001282 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001283 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001284 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001285 { .name = "readlink", .errmsg = true,
1286 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001287 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001288 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1289 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001290 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001291 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001292 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001293 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1294 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001295 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001296 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1297 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001298 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001299 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1300 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001301 { .name = "removexattr", .errmsg = true,
1302 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001303 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001304 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001305 { .name = "rmdir", .errmsg = true,
1306 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001307 { .name = "rt_sigaction", .errmsg = true,
1308 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001309 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001310 { .name = "rt_sigqueueinfo", .errmsg = true,
1311 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1312 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1313 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001314 { .name = "sched_setscheduler", .errmsg = true,
1315 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001316 { .name = "seccomp", .errmsg = true,
1317 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
1318 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001319 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001320 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001321 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1322 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001323 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001324 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1325 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001326 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001327 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1328 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001329 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001330 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1331 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001332 { .name = "setxattr", .errmsg = true,
1333 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001334 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001335 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001336 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001337 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1338 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001339 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001340 { .name = "socketpair", .errmsg = true,
1341 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1342 [1] = SCA_SK_TYPE, /* type */ },
1343 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001344 { .name = "stat", .errmsg = true, .alias = "newstat",
1345 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001346 { .name = "statfs", .errmsg = true,
1347 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1348 { .name = "swapoff", .errmsg = true,
1349 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1350 { .name = "swapon", .errmsg = true,
1351 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001352 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001353 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001354 { .name = "tgkill", .errmsg = true,
1355 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1356 { .name = "tkill", .errmsg = true,
1357 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001358 { .name = "truncate", .errmsg = true,
1359 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001360 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001361 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001362 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1363 [1] = SCA_FILENAME, /* pathname */ }, },
1364 { .name = "utime", .errmsg = true,
1365 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001366 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001367 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1368 [1] = SCA_FILENAME, /* filename */ }, },
1369 { .name = "utimes", .errmsg = true,
1370 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001371 { .name = "vmsplice", .errmsg = true,
1372 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001373 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001374 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001375 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001376 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001377 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001378 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001379 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001380 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001381};
1382
1383static int syscall_fmt__cmp(const void *name, const void *fmtp)
1384{
1385 const struct syscall_fmt *fmt = fmtp;
1386 return strcmp(name, fmt->name);
1387}
1388
1389static struct syscall_fmt *syscall_fmt__find(const char *name)
1390{
1391 const int nmemb = ARRAY_SIZE(syscall_fmts);
1392 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1393}
1394
1395struct syscall {
1396 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001397 int nr_args;
1398 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001399 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001400 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001401 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001402 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001403 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001404};
1405
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001406static size_t fprintf_duration(unsigned long t, FILE *fp)
1407{
1408 double duration = (double)t / NSEC_PER_MSEC;
1409 size_t printed = fprintf(fp, "(");
1410
1411 if (duration >= 1.0)
1412 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1413 else if (duration >= 0.01)
1414 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1415 else
1416 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001417 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001418}
1419
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001420/**
1421 * filename.ptr: The filename char pointer that will be vfs_getname'd
1422 * filename.entry_str_pos: Where to insert the string translated from
1423 * filename.ptr by the vfs_getname tracepoint/kprobe.
1424 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001425struct thread_trace {
1426 u64 entry_time;
1427 u64 exit_time;
1428 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001429 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001430 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001431 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001432 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001433 struct {
1434 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001435 short int entry_str_pos;
1436 bool pending_open;
1437 unsigned int namelen;
1438 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001439 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001440 struct {
1441 int max;
1442 char **table;
1443 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001444
1445 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001446};
1447
1448static struct thread_trace *thread_trace__new(void)
1449{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001450 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1451
1452 if (ttrace)
1453 ttrace->paths.max = -1;
1454
David Ahernbf2575c2013-10-08 21:26:53 -06001455 ttrace->syscall_stats = intlist__new(NULL);
1456
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001457 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001458}
1459
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001460static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001461{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001462 struct thread_trace *ttrace;
1463
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001464 if (thread == NULL)
1465 goto fail;
1466
Namhyung Kim89dceb22014-10-06 09:46:03 +09001467 if (thread__priv(thread) == NULL)
1468 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001469
Namhyung Kim89dceb22014-10-06 09:46:03 +09001470 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001471 goto fail;
1472
Namhyung Kim89dceb22014-10-06 09:46:03 +09001473 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001474 ++ttrace->nr_events;
1475
1476 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001477fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001478 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001479 "WARNING: not enough memory, dropping samples!\n");
1480 return NULL;
1481}
1482
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001483#define TRACE_PFMAJ (1 << 0)
1484#define TRACE_PFMIN (1 << 1)
1485
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001486static const size_t trace__entry_str_size = 2048;
1487
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001488struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001489 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001490 struct {
1491 int machine;
1492 int open_id;
1493 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001494 struct {
1495 int max;
1496 struct syscall *table;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001497 struct {
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001498 struct perf_evsel *sys_enter,
1499 *sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001500 } events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001501 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001502 struct record_opts opts;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001503 struct perf_evlist *evlist;
David Ahern8fb598e2013-09-28 13:13:00 -06001504 struct machine *host;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001505 struct thread *current;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001506 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001507 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001508 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001509 struct strlist *ev_qualifier;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001510 struct {
1511 size_t nr;
1512 int *entries;
1513 } ev_qualifier_ids;
David Ahernbdc89662013-08-28 22:29:53 -06001514 struct intlist *tid_list;
1515 struct intlist *pid_list;
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08001516 struct {
1517 size_t nr;
1518 pid_t *entries;
1519 } filter_pids;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001520 double duration_filter;
1521 double runtime_ms;
1522 struct {
1523 u64 vfs_getname,
1524 proc_getname;
1525 } stats;
1526 bool not_ev_qualifier;
1527 bool live;
1528 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001529 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001530 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001531 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001532 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001533 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001534 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001535 bool trace_syscalls;
Yunlong Songe366a6d2015-04-02 21:47:18 +08001536 bool force;
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03001537 bool vfs_getname;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001538 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001539};
1540
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001541static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001542{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001543 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001544
1545 if (fd > ttrace->paths.max) {
1546 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1547
1548 if (npath == NULL)
1549 return -1;
1550
1551 if (ttrace->paths.max != -1) {
1552 memset(npath + ttrace->paths.max + 1, 0,
1553 (fd - ttrace->paths.max) * sizeof(char *));
1554 } else {
1555 memset(npath, 0, (fd + 1) * sizeof(char *));
1556 }
1557
1558 ttrace->paths.table = npath;
1559 ttrace->paths.max = fd;
1560 }
1561
1562 ttrace->paths.table[fd] = strdup(pathname);
1563
1564 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1565}
1566
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001567static int thread__read_fd_path(struct thread *thread, int fd)
1568{
1569 char linkname[PATH_MAX], pathname[PATH_MAX];
1570 struct stat st;
1571 int ret;
1572
1573 if (thread->pid_ == thread->tid) {
1574 scnprintf(linkname, sizeof(linkname),
1575 "/proc/%d/fd/%d", thread->pid_, fd);
1576 } else {
1577 scnprintf(linkname, sizeof(linkname),
1578 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1579 }
1580
1581 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1582 return -1;
1583
1584 ret = readlink(linkname, pathname, sizeof(pathname));
1585
1586 if (ret < 0 || ret > st.st_size)
1587 return -1;
1588
1589 pathname[ret] = '\0';
1590 return trace__set_fd_pathname(thread, fd, pathname);
1591}
1592
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001593static const char *thread__fd_path(struct thread *thread, int fd,
1594 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001595{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001596 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001597
1598 if (ttrace == NULL)
1599 return NULL;
1600
1601 if (fd < 0)
1602 return NULL;
1603
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001604 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001605 if (!trace->live)
1606 return NULL;
1607 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001608 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001609 return NULL;
1610 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001611
1612 return ttrace->paths.table[fd];
1613}
1614
1615static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1616 struct syscall_arg *arg)
1617{
1618 int fd = arg->val;
1619 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001620 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001621
1622 if (path)
1623 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1624
1625 return printed;
1626}
1627
1628static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1629 struct syscall_arg *arg)
1630{
1631 int fd = arg->val;
1632 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001633 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001634
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001635 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1636 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001637
1638 return printed;
1639}
1640
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001641static void thread__set_filename_pos(struct thread *thread, const char *bf,
1642 unsigned long ptr)
1643{
1644 struct thread_trace *ttrace = thread__priv(thread);
1645
1646 ttrace->filename.ptr = ptr;
1647 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1648}
1649
1650static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1651 struct syscall_arg *arg)
1652{
1653 unsigned long ptr = arg->val;
1654
1655 if (!arg->trace->vfs_getname)
1656 return scnprintf(bf, size, "%#x", ptr);
1657
1658 thread__set_filename_pos(arg->thread, bf, ptr);
1659 return 0;
1660}
1661
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001662static bool trace__filter_duration(struct trace *trace, double t)
1663{
1664 return t < (trace->duration_filter * NSEC_PER_MSEC);
1665}
1666
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001667static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1668{
1669 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1670
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001671 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001672}
1673
Namhyung Kimf15eb532012-10-05 14:02:16 +09001674static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001675static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001676
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001677static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001678{
1679 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001680 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001681}
1682
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001683static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001684 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001685{
1686 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001687 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001688
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001689 if (trace->multiple_threads) {
1690 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001691 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001692 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001693 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001694
1695 return printed;
1696}
1697
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001698static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001699 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001700{
1701 int ret = 0;
1702
1703 switch (event->header.type) {
1704 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001705 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001706 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001707 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001708 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001709 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001710 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001711 break;
1712 }
1713
1714 return ret;
1715}
1716
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001717static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001718 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001719 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001720 struct machine *machine)
1721{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001722 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001723 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001724}
1725
1726static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1727{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001728 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001729
1730 if (err)
1731 return err;
1732
David Ahern8fb598e2013-09-28 13:13:00 -06001733 trace->host = machine__new_host();
1734 if (trace->host == NULL)
1735 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001736
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001737 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001738 return -errno;
1739
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001740 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001741 evlist->threads, trace__tool_process, false,
1742 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001743 if (err)
1744 symbol__exit();
1745
1746 return err;
1747}
1748
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001749static int syscall__set_arg_fmts(struct syscall *sc)
1750{
1751 struct format_field *field;
1752 int idx = 0;
1753
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001754 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001755 if (sc->arg_scnprintf == NULL)
1756 return -1;
1757
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001758 if (sc->fmt)
1759 sc->arg_parm = sc->fmt->arg_parm;
1760
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001761 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001762 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1763 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1764 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001765 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1766 ++idx;
1767 }
1768
1769 return 0;
1770}
1771
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001772static int trace__read_syscall_info(struct trace *trace, int id)
1773{
1774 char tp_name[128];
1775 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001776 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001777
1778 if (name == NULL)
1779 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001780
1781 if (id > trace->syscalls.max) {
1782 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1783
1784 if (nsyscalls == NULL)
1785 return -1;
1786
1787 if (trace->syscalls.max != -1) {
1788 memset(nsyscalls + trace->syscalls.max + 1, 0,
1789 (id - trace->syscalls.max) * sizeof(*sc));
1790 } else {
1791 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1792 }
1793
1794 trace->syscalls.table = nsyscalls;
1795 trace->syscalls.max = id;
1796 }
1797
1798 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001799 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001800
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001801 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001802
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001803 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001804 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001805
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001806 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001807 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001808 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001809 }
1810
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001811 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001812 return -1;
1813
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001814 sc->args = sc->tp_format->format.fields;
1815 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001816 /*
1817 * We need to check and discard the first variable '__syscall_nr'
1818 * or 'nr' that mean the syscall number. It is needless here.
1819 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1820 */
1821 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001822 sc->args = sc->args->next;
1823 --sc->nr_args;
1824 }
1825
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001826 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1827
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001828 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001829}
1830
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001831static int trace__validate_ev_qualifier(struct trace *trace)
1832{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001833 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001834 struct str_node *pos;
1835
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001836 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1837 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1838 sizeof(trace->ev_qualifier_ids.entries[0]));
1839
1840 if (trace->ev_qualifier_ids.entries == NULL) {
1841 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1842 trace->output);
1843 err = -EINVAL;
1844 goto out;
1845 }
1846
1847 i = 0;
1848
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001849 strlist__for_each(pos, trace->ev_qualifier) {
1850 const char *sc = pos->s;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001851 int id = audit_name_to_syscall(sc, trace->audit.machine);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001852
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001853 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001854 if (err == 0) {
1855 fputs("Error:\tInvalid syscall ", trace->output);
1856 err = -EINVAL;
1857 } else {
1858 fputs(", ", trace->output);
1859 }
1860
1861 fputs(sc, trace->output);
1862 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001863
1864 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001865 }
1866
1867 if (err < 0) {
1868 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1869 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001870 zfree(&trace->ev_qualifier_ids.entries);
1871 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001872 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001873out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001874 return err;
1875}
1876
David Ahern55d43bc2015-02-19 15:00:22 -05001877/*
1878 * args is to be interpreted as a series of longs but we need to handle
1879 * 8-byte unaligned accesses. args points to raw_data within the event
1880 * and raw_data is guaranteed to be 8-byte unaligned because it is
1881 * preceded by raw_size which is a u32. So we need to copy args to a temp
1882 * variable to read it. Most notably this avoids extended load instructions
1883 * on unaligned addresses
1884 */
1885
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001886static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001887 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001888 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001889{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001890 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001891 unsigned char *p;
1892 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001893
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001894 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001895 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001896 u8 bit = 1;
1897 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001898 .idx = 0,
1899 .mask = 0,
1900 .trace = trace,
1901 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001902 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001903
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001904 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001905 field = field->next, ++arg.idx, bit <<= 1) {
1906 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001907 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001908
1909 /* special care for unaligned accesses */
1910 p = args + sizeof(unsigned long) * arg.idx;
1911 memcpy(&val, p, sizeof(val));
1912
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001913 /*
1914 * Suppress this argument if its value is zero and
1915 * and we don't have a string associated in an
1916 * strarray for it.
1917 */
David Ahern55d43bc2015-02-19 15:00:22 -05001918 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001919 !(sc->arg_scnprintf &&
1920 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1921 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001922 continue;
1923
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001924 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001925 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001926 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001927 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001928 if (sc->arg_parm)
1929 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001930 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1931 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001932 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001933 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001934 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001935 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001936 }
1937 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001938 int i = 0;
1939
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001940 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001941 /* special care for unaligned accesses */
1942 p = args + sizeof(unsigned long) * i;
1943 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001944 printed += scnprintf(bf + printed, size - printed,
1945 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001946 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001947 ++i;
1948 }
1949 }
1950
1951 return printed;
1952}
1953
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001954typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001955 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001956 struct perf_sample *sample);
1957
1958static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001959 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001960{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001961
1962 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001963
1964 /*
1965 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1966 * before that, leaving at a higher verbosity level till that is
1967 * explained. Reproduced with plain ftrace with:
1968 *
1969 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1970 * grep "NR -1 " /t/trace_pipe
1971 *
1972 * After generating some load on the machine.
1973 */
1974 if (verbose > 1) {
1975 static u64 n;
1976 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1977 id, perf_evsel__name(evsel), ++n);
1978 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001979 return NULL;
1980 }
1981
1982 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1983 trace__read_syscall_info(trace, id))
1984 goto out_cant_read;
1985
1986 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1987 goto out_cant_read;
1988
1989 return &trace->syscalls.table[id];
1990
1991out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001992 if (verbose) {
1993 fprintf(trace->output, "Problems reading syscall %d", id);
1994 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1995 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1996 fputs(" information\n", trace->output);
1997 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001998 return NULL;
1999}
2000
David Ahernbf2575c2013-10-08 21:26:53 -06002001static void thread__update_stats(struct thread_trace *ttrace,
2002 int id, struct perf_sample *sample)
2003{
2004 struct int_node *inode;
2005 struct stats *stats;
2006 u64 duration = 0;
2007
2008 inode = intlist__findnew(ttrace->syscall_stats, id);
2009 if (inode == NULL)
2010 return;
2011
2012 stats = inode->priv;
2013 if (stats == NULL) {
2014 stats = malloc(sizeof(struct stats));
2015 if (stats == NULL)
2016 return;
2017 init_stats(stats);
2018 inode->priv = stats;
2019 }
2020
2021 if (ttrace->entry_time && sample->time > ttrace->entry_time)
2022 duration = sample->time - ttrace->entry_time;
2023
2024 update_stats(stats, duration);
2025}
2026
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03002027static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
2028{
2029 struct thread_trace *ttrace;
2030 u64 duration;
2031 size_t printed;
2032
2033 if (trace->current == NULL)
2034 return 0;
2035
2036 ttrace = thread__priv(trace->current);
2037
2038 if (!ttrace->entry_pending)
2039 return 0;
2040
2041 duration = sample->time - ttrace->entry_time;
2042
2043 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
2044 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
2045 ttrace->entry_pending = false;
2046
2047 return printed;
2048}
2049
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002050static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002051 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002052 struct perf_sample *sample)
2053{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002054 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002055 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002056 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002057 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002058 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002059 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002060 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002061
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002062 if (sc == NULL)
2063 return -1;
2064
David Ahern8fb598e2013-09-28 13:13:00 -06002065 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002066 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002067 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002068 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002069
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002070 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002071
2072 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002073 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002074 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002075 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002076 }
2077
David Ahern13f22a22015-03-19 12:23:03 -06002078 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03002079 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03002080
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002081 ttrace->entry_time = sample->time;
2082 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002083 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002084
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002085 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002086 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002087
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03002088 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07002089 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002090 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
2091 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002092 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002093 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002094 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002095 /* See trace__vfs_getname & trace__sys_exit */
2096 ttrace->filename.pending_open = false;
2097 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002098
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002099 if (trace->current != thread) {
2100 thread__put(trace->current);
2101 trace->current = thread__get(thread);
2102 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002103 err = 0;
2104out_put:
2105 thread__put(thread);
2106 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002107}
2108
2109static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002110 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002111 struct perf_sample *sample)
2112{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002113 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002114 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002115 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002116 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002117 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002118 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002119
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002120 if (sc == NULL)
2121 return -1;
2122
David Ahern8fb598e2013-09-28 13:13:00 -06002123 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002124 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002125 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002126 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002127
David Ahernbf2575c2013-10-08 21:26:53 -06002128 if (trace->summary)
2129 thread__update_stats(ttrace, id, sample);
2130
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002131 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002132
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002133 if (id == trace->audit.open_id && ret >= 0 && ttrace->filename.pending_open) {
2134 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
2135 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002136 ++trace->stats.vfs_getname;
2137 }
2138
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002139 ttrace->exit_time = sample->time;
2140
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002141 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002142 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002143 if (trace__filter_duration(trace, duration))
2144 goto out;
2145 } else if (trace->duration_filter)
2146 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002147
David Ahernfd2eaba2013-11-12 09:31:15 -07002148 if (trace->summary_only)
2149 goto out;
2150
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002151 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002152
2153 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002154 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002155 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002156 fprintf(trace->output, " ... [");
2157 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
2158 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002159 }
2160
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002161 if (sc->fmt == NULL) {
2162signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002163 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03002164 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00002165 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002166 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
2167 *e = audit_errno_to_name(-ret);
2168
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002169 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002170 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002171 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03002172 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002173 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03002174 else if (sc->fmt->errpid) {
2175 struct thread *child = machine__find_thread(trace->host, ret, ret);
2176
2177 if (child != NULL) {
2178 fprintf(trace->output, ") = %ld", ret);
2179 if (child->comm_set)
2180 fprintf(trace->output, " (%s)", thread__comm_str(child));
2181 thread__put(child);
2182 }
2183 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002184 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002185
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002186 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002187out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002188 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002189 err = 0;
2190out_put:
2191 thread__put(thread);
2192 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002193}
2194
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002195static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002196 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002197 struct perf_sample *sample)
2198{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002199 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2200 struct thread_trace *ttrace;
2201 size_t filename_len, entry_str_len, to_move;
2202 ssize_t remaining_space;
2203 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002204 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002205
2206 if (!thread)
2207 goto out;
2208
2209 ttrace = thread__priv(thread);
2210 if (!ttrace)
2211 goto out;
2212
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002213 filename_len = strlen(filename);
2214
2215 if (ttrace->filename.namelen < filename_len) {
2216 char *f = realloc(ttrace->filename.name, filename_len + 1);
2217
2218 if (f == NULL)
2219 goto out;
2220
2221 ttrace->filename.namelen = filename_len;
2222 ttrace->filename.name = f;
2223 }
2224
2225 strcpy(ttrace->filename.name, filename);
2226 ttrace->filename.pending_open = true;
2227
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002228 if (!ttrace->filename.ptr)
2229 goto out;
2230
2231 entry_str_len = strlen(ttrace->entry_str);
2232 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2233 if (remaining_space <= 0)
2234 goto out;
2235
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002236 if (filename_len > (size_t)remaining_space) {
2237 filename += filename_len - remaining_space;
2238 filename_len = remaining_space;
2239 }
2240
2241 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2242 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2243 memmove(pos + filename_len, pos, to_move);
2244 memcpy(pos, filename, filename_len);
2245
2246 ttrace->filename.ptr = 0;
2247 ttrace->filename.entry_str_pos = 0;
2248out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002249 return 0;
2250}
2251
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002252static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002253 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002254 struct perf_sample *sample)
2255{
2256 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2257 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06002258 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03002259 sample->pid,
2260 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002261 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002262
2263 if (ttrace == NULL)
2264 goto out_dump;
2265
2266 ttrace->runtime_ms += runtime_ms;
2267 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002268 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002269 return 0;
2270
2271out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002272 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002273 evsel->name,
2274 perf_evsel__strval(evsel, sample, "comm"),
2275 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2276 runtime,
2277 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002278 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002279 return 0;
2280}
2281
Wang Nan1d6c9402016-02-26 09:31:55 +00002282static void bpf_output__printer(enum binary_printer_ops op,
2283 unsigned int val, void *extra)
2284{
2285 FILE *output = extra;
2286 unsigned char ch = (unsigned char)val;
2287
2288 switch (op) {
2289 case BINARY_PRINT_CHAR_DATA:
2290 fprintf(output, "%c", isprint(ch) ? ch : '.');
2291 break;
2292 case BINARY_PRINT_DATA_BEGIN:
2293 case BINARY_PRINT_LINE_BEGIN:
2294 case BINARY_PRINT_ADDR:
2295 case BINARY_PRINT_NUM_DATA:
2296 case BINARY_PRINT_NUM_PAD:
2297 case BINARY_PRINT_SEP:
2298 case BINARY_PRINT_CHAR_PAD:
2299 case BINARY_PRINT_LINE_END:
2300 case BINARY_PRINT_DATA_END:
2301 default:
2302 break;
2303 }
2304}
2305
2306static void bpf_output__fprintf(struct trace *trace,
2307 struct perf_sample *sample)
2308{
2309 print_binary(sample->raw_data, sample->raw_size, 8,
2310 bpf_output__printer, trace->output);
2311}
2312
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002313static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2314 union perf_event *event __maybe_unused,
2315 struct perf_sample *sample)
2316{
2317 trace__printf_interrupted_entry(trace, sample);
2318 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002319
2320 if (trace->trace_syscalls)
2321 fprintf(trace->output, "( ): ");
2322
2323 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002324
Wang Nan1d6c9402016-02-26 09:31:55 +00002325 if (perf_evsel__is_bpf_output(evsel)) {
2326 bpf_output__fprintf(trace, sample);
2327 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002328 event_format__fprintf(evsel->tp_format, sample->cpu,
2329 sample->raw_data, sample->raw_size,
2330 trace->output);
2331 }
2332
2333 fprintf(trace->output, ")\n");
2334 return 0;
2335}
2336
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002337static void print_location(FILE *f, struct perf_sample *sample,
2338 struct addr_location *al,
2339 bool print_dso, bool print_sym)
2340{
2341
2342 if ((verbose || print_dso) && al->map)
2343 fprintf(f, "%s@", al->map->dso->long_name);
2344
2345 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002346 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002347 al->addr - al->sym->start);
2348 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002349 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002350 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002351 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002352}
2353
2354static int trace__pgfault(struct trace *trace,
2355 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002356 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002357 struct perf_sample *sample)
2358{
2359 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002360 struct addr_location al;
2361 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002362 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002363 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002364
2365 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002366 ttrace = thread__trace(thread, trace->output);
2367 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002368 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002369
2370 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2371 ttrace->pfmaj++;
2372 else
2373 ttrace->pfmin++;
2374
2375 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002376 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002377
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002378 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002379 sample->ip, &al);
2380
2381 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2382
2383 fprintf(trace->output, "%sfault [",
2384 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2385 "maj" : "min");
2386
2387 print_location(trace->output, sample, &al, false, true);
2388
2389 fprintf(trace->output, "] => ");
2390
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002391 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002392 sample->addr, &al);
2393
2394 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002395 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002396 MAP__FUNCTION, sample->addr, &al);
2397
2398 if (al.map)
2399 map_type = 'x';
2400 else
2401 map_type = '?';
2402 }
2403
2404 print_location(trace->output, sample, &al, true, false);
2405
2406 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002407out:
2408 err = 0;
2409out_put:
2410 thread__put(thread);
2411 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002412}
2413
David Ahernbdc89662013-08-28 22:29:53 -06002414static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2415{
2416 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2417 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2418 return false;
2419
2420 if (trace->pid_list || trace->tid_list)
2421 return true;
2422
2423 return false;
2424}
2425
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002426static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002427 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002428 struct perf_sample *sample)
2429{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002430 /*
2431 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2432 * and don't use sample->time unconditionally, we may end up having
2433 * some other event in the future without PERF_SAMPLE_TIME for good
2434 * reason, i.e. we may not be interested in its timestamps, just in
2435 * it taking place, picking some piece of information when it
2436 * appears in our event stream (vfs_getname comes to mind).
2437 */
2438 if (trace->base_time == 0 && !trace->full_time &&
2439 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002440 trace->base_time = sample->time;
2441}
2442
David Ahern6810fc92013-08-28 22:29:52 -06002443static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002444 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002445 struct perf_sample *sample,
2446 struct perf_evsel *evsel,
2447 struct machine *machine __maybe_unused)
2448{
2449 struct trace *trace = container_of(tool, struct trace, tool);
2450 int err = 0;
2451
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002452 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002453
David Ahernbdc89662013-08-28 22:29:53 -06002454 if (skip_sample(trace, sample))
2455 return 0;
2456
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002457 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002458
David Ahern31605652013-12-04 19:41:41 -07002459 if (handler) {
2460 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002461 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002462 }
David Ahern6810fc92013-08-28 22:29:52 -06002463
2464 return err;
2465}
2466
David Ahernbdc89662013-08-28 22:29:53 -06002467static int parse_target_str(struct trace *trace)
2468{
2469 if (trace->opts.target.pid) {
2470 trace->pid_list = intlist__new(trace->opts.target.pid);
2471 if (trace->pid_list == NULL) {
2472 pr_err("Error parsing process id string\n");
2473 return -EINVAL;
2474 }
2475 }
2476
2477 if (trace->opts.target.tid) {
2478 trace->tid_list = intlist__new(trace->opts.target.tid);
2479 if (trace->tid_list == NULL) {
2480 pr_err("Error parsing thread id string\n");
2481 return -EINVAL;
2482 }
2483 }
2484
2485 return 0;
2486}
2487
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002488static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002489{
2490 unsigned int rec_argc, i, j;
2491 const char **rec_argv;
2492 const char * const record_args[] = {
2493 "record",
2494 "-R",
2495 "-m", "1024",
2496 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002497 };
2498
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002499 const char * const sc_args[] = { "-e", };
2500 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2501 const char * const majpf_args[] = { "-e", "major-faults" };
2502 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2503 const char * const minpf_args[] = { "-e", "minor-faults" };
2504 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2505
David Ahern9aca7f12013-12-04 19:41:39 -07002506 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002507 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2508 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002509 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2510
2511 if (rec_argv == NULL)
2512 return -ENOMEM;
2513
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002514 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002515 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002516 rec_argv[j++] = record_args[i];
2517
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002518 if (trace->trace_syscalls) {
2519 for (i = 0; i < sc_args_nr; i++)
2520 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002521
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002522 /* event string may be different for older kernels - e.g., RHEL6 */
2523 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2524 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2525 else if (is_valid_tracepoint("syscalls:sys_enter"))
2526 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2527 else {
2528 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2529 return -1;
2530 }
David Ahern9aca7f12013-12-04 19:41:39 -07002531 }
David Ahern9aca7f12013-12-04 19:41:39 -07002532
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002533 if (trace->trace_pgfaults & TRACE_PFMAJ)
2534 for (i = 0; i < majpf_args_nr; i++)
2535 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002536
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002537 if (trace->trace_pgfaults & TRACE_PFMIN)
2538 for (i = 0; i < minpf_args_nr; i++)
2539 rec_argv[j++] = minpf_args[i];
2540
2541 for (i = 0; i < (unsigned int)argc; i++)
2542 rec_argv[j++] = argv[i];
2543
2544 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002545}
2546
David Ahernbf2575c2013-10-08 21:26:53 -06002547static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2548
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002549static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002550{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002551 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002552
2553 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002554 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002555
2556 if (perf_evsel__field(evsel, "pathname") == NULL) {
2557 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002558 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002559 }
2560
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002561 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002562 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002563 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002564}
2565
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002566static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2567 u64 config)
2568{
2569 struct perf_evsel *evsel;
2570 struct perf_event_attr attr = {
2571 .type = PERF_TYPE_SOFTWARE,
2572 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002573 };
2574
2575 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002576 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002577
2578 event_attr_init(&attr);
2579
2580 evsel = perf_evsel__new(&attr);
2581 if (!evsel)
2582 return -ENOMEM;
2583
2584 evsel->handler = trace__pgfault;
2585 perf_evlist__add(evlist, evsel);
2586
2587 return 0;
2588}
2589
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002590static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2591{
2592 const u32 type = event->header.type;
2593 struct perf_evsel *evsel;
2594
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002595 if (type != PERF_RECORD_SAMPLE) {
2596 trace__process_event(trace, trace->host, event, sample);
2597 return;
2598 }
2599
2600 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2601 if (evsel == NULL) {
2602 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2603 return;
2604 }
2605
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002606 trace__set_base_time(trace, evsel, sample);
2607
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002608 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2609 sample->raw_data == NULL) {
2610 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2611 perf_evsel__name(evsel), sample->tid,
2612 sample->cpu, sample->raw_size);
2613 } else {
2614 tracepoint_handler handler = evsel->handler;
2615 handler(trace, evsel, event, sample);
2616 }
2617}
2618
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002619static int trace__add_syscall_newtp(struct trace *trace)
2620{
2621 int ret = -1;
2622 struct perf_evlist *evlist = trace->evlist;
2623 struct perf_evsel *sys_enter, *sys_exit;
2624
2625 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2626 if (sys_enter == NULL)
2627 goto out;
2628
2629 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2630 goto out_delete_sys_enter;
2631
2632 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2633 if (sys_exit == NULL)
2634 goto out_delete_sys_enter;
2635
2636 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2637 goto out_delete_sys_exit;
2638
2639 perf_evlist__add(evlist, sys_enter);
2640 perf_evlist__add(evlist, sys_exit);
2641
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002642 trace->syscalls.events.sys_enter = sys_enter;
2643 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002644
2645 ret = 0;
2646out:
2647 return ret;
2648
2649out_delete_sys_exit:
2650 perf_evsel__delete_priv(sys_exit);
2651out_delete_sys_enter:
2652 perf_evsel__delete_priv(sys_enter);
2653 goto out;
2654}
2655
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002656static int trace__set_ev_qualifier_filter(struct trace *trace)
2657{
2658 int err = -1;
2659 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2660 trace->ev_qualifier_ids.nr,
2661 trace->ev_qualifier_ids.entries);
2662
2663 if (filter == NULL)
2664 goto out_enomem;
2665
2666 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2667 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2668
2669 free(filter);
2670out:
2671 return err;
2672out_enomem:
2673 errno = ENOMEM;
2674 goto out;
2675}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002676
Namhyung Kimf15eb532012-10-05 14:02:16 +09002677static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002678{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002679 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002680 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002681 int err = -1, i;
2682 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002683 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002684 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002685
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002686 trace->live = true;
2687
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002688 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002689 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002690
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002691 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002692 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002693
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002694 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002695 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002696 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002697 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002698
2699 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2700 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002701 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002702
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002703 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002704 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2705 trace__sched_stat_runtime))
2706 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002707
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002708 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2709 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002710 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002711 goto out_delete_evlist;
2712 }
2713
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002714 err = trace__symbols_init(trace, evlist);
2715 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002716 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002717 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002718 }
2719
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002720 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002721
Namhyung Kimf15eb532012-10-05 14:02:16 +09002722 signal(SIGCHLD, sig_handler);
2723 signal(SIGINT, sig_handler);
2724
2725 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002726 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002727 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002728 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002729 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002730 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002731 }
2732 }
2733
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002734 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002735 if (err < 0)
2736 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002737
Wang Nanba504232016-02-26 09:31:54 +00002738 err = bpf__apply_obj_config();
2739 if (err) {
2740 char errbuf[BUFSIZ];
2741
2742 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2743 pr_err("ERROR: Apply config to BPF failed: %s\n",
2744 errbuf);
2745 goto out_error_open;
2746 }
2747
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002748 /*
2749 * Better not use !target__has_task() here because we need to cover the
2750 * case where no threads were specified in the command line, but a
2751 * workload was, and in that case we will fill in the thread_map when
2752 * we fork the workload in perf_evlist__prepare_workload.
2753 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002754 if (trace->filter_pids.nr > 0)
2755 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002756 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002757 err = perf_evlist__set_filter_pid(evlist, getpid());
2758
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002759 if (err < 0)
2760 goto out_error_mem;
2761
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002762 if (trace->ev_qualifier_ids.nr > 0) {
2763 err = trace__set_ev_qualifier_filter(trace);
2764 if (err < 0)
2765 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002766
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002767 pr_debug("event qualifier tracepoint filter: %s\n",
2768 trace->syscalls.events.sys_exit->filter);
2769 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002770
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002771 err = perf_evlist__apply_filters(evlist, &evsel);
2772 if (err < 0)
2773 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002774
Jiri Olsaf8850372013-11-28 17:57:22 +01002775 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002776 if (err < 0)
2777 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002778
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002779 if (!target__none(&trace->opts.target))
2780 perf_evlist__enable(evlist);
2781
Namhyung Kimf15eb532012-10-05 14:02:16 +09002782 if (forks)
2783 perf_evlist__start_workload(evlist);
2784
Jiri Olsae13798c2015-06-23 00:36:02 +02002785 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002786 evlist->threads->nr > 1 ||
2787 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002788again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002789 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002790
2791 for (i = 0; i < evlist->nr_mmaps; i++) {
2792 union perf_event *event;
2793
2794 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002795 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002796
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002797 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002798
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002799 err = perf_evlist__parse_sample(evlist, event, &sample);
2800 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002801 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002802 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002803 }
2804
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002805 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002806next_event:
2807 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002808
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002809 if (interrupted)
2810 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002811
2812 if (done && !draining) {
2813 perf_evlist__disable(evlist);
2814 draining = true;
2815 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002816 }
2817 }
2818
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002819 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002820 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002821
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002822 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2823 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2824 draining = true;
2825
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002826 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002827 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002828 } else {
2829 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002830 }
2831
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002832out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002833 thread__zput(trace->current);
2834
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002835 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002836
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002837 if (!err) {
2838 if (trace->summary)
2839 trace__fprintf_thread_summary(trace, trace->output);
2840
2841 if (trace->show_tool_stats) {
2842 fprintf(trace->output, "Stats:\n "
2843 " vfs_getname : %" PRIu64 "\n"
2844 " proc_getname: %" PRIu64 "\n",
2845 trace->stats.vfs_getname,
2846 trace->stats.proc_getname);
2847 }
2848 }
David Ahernbf2575c2013-10-08 21:26:53 -06002849
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002850out_delete_evlist:
2851 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002852 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002853 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002854 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002855{
2856 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002857
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002858out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002859 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002860 goto out_error;
2861
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002862out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002863 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002864 goto out_error;
2865
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002866out_error_mmap:
2867 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2868 goto out_error;
2869
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002870out_error_open:
2871 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2872
2873out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002874 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302875 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002876
2877out_error_apply_filters:
2878 fprintf(trace->output,
2879 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2880 evsel->filter, perf_evsel__name(evsel), errno,
2881 strerror_r(errno, errbuf, sizeof(errbuf)));
2882 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002883}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002884out_error_mem:
2885 fprintf(trace->output, "Not enough memory to run!\n");
2886 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002887
2888out_errno:
2889 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2890 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002891}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002892
David Ahern6810fc92013-08-28 22:29:52 -06002893static int trace__replay(struct trace *trace)
2894{
2895 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002896 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002897 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002898 struct perf_data_file file = {
2899 .path = input_name,
2900 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002901 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002902 };
David Ahern6810fc92013-08-28 22:29:52 -06002903 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002904 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002905 int err = -1;
2906
2907 trace->tool.sample = trace__process_sample;
2908 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002909 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002910 trace->tool.comm = perf_event__process_comm;
2911 trace->tool.exit = perf_event__process_exit;
2912 trace->tool.fork = perf_event__process_fork;
2913 trace->tool.attr = perf_event__process_attr;
2914 trace->tool.tracing_data = perf_event__process_tracing_data;
2915 trace->tool.build_id = perf_event__process_build_id;
2916
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002917 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002918 trace->tool.ordering_requires_timestamps = true;
2919
2920 /* add tid to output */
2921 trace->multiple_threads = true;
2922
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002923 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002924 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002925 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002926
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002927 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002928 goto out;
2929
David Ahern8fb598e2013-09-28 13:13:00 -06002930 trace->host = &session->machines.host;
2931
David Ahern6810fc92013-08-28 22:29:52 -06002932 err = perf_session__set_tracepoints_handlers(session, handlers);
2933 if (err)
2934 goto out;
2935
Namhyung Kim003824e2013-11-12 15:25:00 +09002936 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2937 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002938 /* older kernels have syscalls tp versus raw_syscalls */
2939 if (evsel == NULL)
2940 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2941 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002942
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002943 if (evsel &&
2944 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2945 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002946 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2947 goto out;
2948 }
2949
2950 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2951 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002952 if (evsel == NULL)
2953 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2954 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002955 if (evsel &&
2956 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2957 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002958 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002959 goto out;
2960 }
2961
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002962 evlist__for_each(session->evlist, evsel) {
2963 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2964 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2965 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2966 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2967 evsel->handler = trace__pgfault;
2968 }
2969
David Ahernbdc89662013-08-28 22:29:53 -06002970 err = parse_target_str(trace);
2971 if (err != 0)
2972 goto out;
2973
David Ahern6810fc92013-08-28 22:29:52 -06002974 setup_pager();
2975
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002976 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002977 if (err)
2978 pr_err("Failed to process events, error %d", err);
2979
David Ahernbf2575c2013-10-08 21:26:53 -06002980 else if (trace->summary)
2981 trace__fprintf_thread_summary(trace, trace->output);
2982
David Ahern6810fc92013-08-28 22:29:52 -06002983out:
2984 perf_session__delete(session);
2985
2986 return err;
2987}
2988
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002989static size_t trace__fprintf_threads_header(FILE *fp)
2990{
2991 size_t printed;
2992
Pekka Enberg99ff7152013-11-12 16:42:14 +02002993 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002994
2995 return printed;
2996}
2997
2998static size_t thread__dump_stats(struct thread_trace *ttrace,
2999 struct trace *trace, FILE *fp)
3000{
3001 struct stats *stats;
3002 size_t printed = 0;
3003 struct syscall *sc;
3004 struct int_node *inode = intlist__first(ttrace->syscall_stats);
3005
3006 if (inode == NULL)
3007 return 0;
3008
3009 printed += fprintf(fp, "\n");
3010
Milian Wolff834fd462015-08-06 11:24:29 +02003011 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
3012 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
3013 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02003014
David Ahernbf2575c2013-10-08 21:26:53 -06003015 /* each int_node is a syscall */
3016 while (inode) {
3017 stats = inode->priv;
3018 if (stats) {
3019 double min = (double)(stats->min) / NSEC_PER_MSEC;
3020 double max = (double)(stats->max) / NSEC_PER_MSEC;
3021 double avg = avg_stats(stats);
3022 double pct;
3023 u64 n = (u64) stats->n;
3024
3025 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
3026 avg /= NSEC_PER_MSEC;
3027
3028 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02003029 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02003030 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
3031 n, avg * n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02003032 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06003033 }
3034
3035 inode = intlist__next(inode);
3036 }
3037
3038 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003039
3040 return printed;
3041}
3042
David Ahern896cbb52013-09-28 13:12:59 -06003043/* struct used to pass data to per-thread function */
3044struct summary_data {
3045 FILE *fp;
3046 struct trace *trace;
3047 size_t printed;
3048};
3049
3050static int trace__fprintf_one_thread(struct thread *thread, void *priv)
3051{
3052 struct summary_data *data = priv;
3053 FILE *fp = data->fp;
3054 size_t printed = data->printed;
3055 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09003056 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06003057 double ratio;
3058
3059 if (ttrace == NULL)
3060 return 0;
3061
3062 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
3063
Pekka Enberg15e65c62013-11-14 18:43:30 +02003064 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003065 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02003066 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04003067 if (ttrace->pfmaj)
3068 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
3069 if (ttrace->pfmin)
3070 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003071 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06003072 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06003073
3074 data->printed += printed;
3075
3076 return 0;
3077}
3078
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003079static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
3080{
David Ahern896cbb52013-09-28 13:12:59 -06003081 struct summary_data data = {
3082 .fp = fp,
3083 .trace = trace
3084 };
3085 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003086
David Ahern896cbb52013-09-28 13:12:59 -06003087 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003088
David Ahern896cbb52013-09-28 13:12:59 -06003089 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003090}
3091
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003092static int trace__set_duration(const struct option *opt, const char *str,
3093 int unset __maybe_unused)
3094{
3095 struct trace *trace = opt->value;
3096
3097 trace->duration_filter = atof(str);
3098 return 0;
3099}
3100
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08003101static int trace__set_filter_pids(const struct option *opt, const char *str,
3102 int unset __maybe_unused)
3103{
3104 int ret = -1;
3105 size_t i;
3106 struct trace *trace = opt->value;
3107 /*
3108 * FIXME: introduce a intarray class, plain parse csv and create a
3109 * { int nr, int entries[] } struct...
3110 */
3111 struct intlist *list = intlist__new(str);
3112
3113 if (list == NULL)
3114 return -1;
3115
3116 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
3117 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
3118
3119 if (trace->filter_pids.entries == NULL)
3120 goto out;
3121
3122 trace->filter_pids.entries[0] = getpid();
3123
3124 for (i = 1; i < trace->filter_pids.nr; ++i)
3125 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
3126
3127 intlist__delete(list);
3128 ret = 0;
3129out:
3130 return ret;
3131}
3132
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003133static int trace__open_output(struct trace *trace, const char *filename)
3134{
3135 struct stat st;
3136
3137 if (!stat(filename, &st) && st.st_size) {
3138 char oldname[PATH_MAX];
3139
3140 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
3141 unlink(oldname);
3142 rename(filename, oldname);
3143 }
3144
3145 trace->output = fopen(filename, "w");
3146
3147 return trace->output == NULL ? -errno : 0;
3148}
3149
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003150static int parse_pagefaults(const struct option *opt, const char *str,
3151 int unset __maybe_unused)
3152{
3153 int *trace_pgfaults = opt->value;
3154
3155 if (strcmp(str, "all") == 0)
3156 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
3157 else if (strcmp(str, "maj") == 0)
3158 *trace_pgfaults |= TRACE_PFMAJ;
3159 else if (strcmp(str, "min") == 0)
3160 *trace_pgfaults |= TRACE_PFMIN;
3161 else
3162 return -1;
3163
3164 return 0;
3165}
3166
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003167static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3168{
3169 struct perf_evsel *evsel;
3170
3171 evlist__for_each(evlist, evsel)
3172 evsel->handler = handler;
3173}
3174
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003175int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3176{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003177 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003178 "perf trace [<options>] [<command>]",
3179 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003180 "perf trace record [<options>] [<command>]",
3181 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003182 NULL
3183 };
3184 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003185 .audit = {
3186 .machine = audit_detect_machine(),
3187 .open_id = audit_name_to_syscall("open", trace.audit.machine),
3188 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003189 .syscalls = {
3190 . max = -1,
3191 },
3192 .opts = {
3193 .target = {
3194 .uid = UINT_MAX,
3195 .uses_mmap = true,
3196 },
3197 .user_freq = UINT_MAX,
3198 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003199 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003200 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003201 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003202 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003203 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003204 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003205 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003206 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003207 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003208 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003209 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003210 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3211 "event selector. use 'perf list' to list available events",
3212 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003213 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3214 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003215 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03003216 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003217 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003218 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003219 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3220 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003221 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003222 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003223 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3224 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003225 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003226 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003227 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003228 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003229 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003230 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003231 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3232 "number of mmap data pages",
3233 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003234 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003235 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003236 OPT_CALLBACK(0, "duration", &trace, "float",
3237 "show only events with duration > N.M ms",
3238 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003239 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003240 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003241 OPT_BOOLEAN('T', "time", &trace.full_time,
3242 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003243 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3244 "Show only syscall summary with statistics"),
3245 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3246 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003247 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3248 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003249 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003250 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003251 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3252 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003253 OPT_END()
3254 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003255 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003256 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003257 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003258
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003259 signal(SIGSEGV, sighandler_dump_stack);
3260 signal(SIGFPE, sighandler_dump_stack);
3261
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003262 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003263
3264 if (trace.evlist == NULL) {
3265 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003266 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003267 goto out;
3268 }
3269
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003270 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3271 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003272
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003273 if (trace.trace_pgfaults) {
3274 trace.opts.sample_address = true;
3275 trace.opts.sample_time = true;
3276 }
3277
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003278 if (trace.evlist->nr_entries > 0)
3279 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3280
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003281 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3282 return trace__record(&trace, argc-1, &argv[1]);
3283
3284 /* summary_only implies summary option, but don't overwrite summary if set */
3285 if (trace.summary_only)
3286 trace.summary = trace.summary_only;
3287
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003288 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3289 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003290 pr_err("Please specify something to trace.\n");
3291 return -1;
3292 }
3293
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003294 if (output_name != NULL) {
3295 err = trace__open_output(&trace, output_name);
3296 if (err < 0) {
3297 perror("failed to create output file");
3298 goto out;
3299 }
3300 }
3301
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003302 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003303 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003304 struct strlist_config slist_config = {
3305 .dirname = system_path(STRACE_GROUPS_DIR),
3306 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003307
3308 trace.not_ev_qualifier = *s == '!';
3309 if (trace.not_ev_qualifier)
3310 ++s;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003311 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003312 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003313 fputs("Not enough memory to parse event qualifier",
3314 trace.output);
3315 err = -ENOMEM;
3316 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003317 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003318
3319 err = trace__validate_ev_qualifier(&trace);
3320 if (err)
3321 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003322 }
3323
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003324 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003325 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003326 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003327 fprintf(trace.output, "%s", bf);
3328 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003329 }
3330
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003331 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003332 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003333 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003334 fprintf(trace.output, "%s", bf);
3335 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003336 }
3337
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003338 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003339 trace.opts.target.system_wide = true;
3340
David Ahern6810fc92013-08-28 22:29:52 -06003341 if (input_name)
3342 err = trace__replay(&trace);
3343 else
3344 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003345
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003346out_close:
3347 if (output_name != NULL)
3348 fclose(trace.output);
3349out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003350 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003351}