blob: 11290b57ce04972dc845c380d50e6ad897744dd8 [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 Melofd0db102016-04-04 13:32:20 -030037#include "syscalltbl.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030038
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030039#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030040#include <stdlib.h>
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030041#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030042#include <linux/futex.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020043#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030044#include <linux/seccomp.h>
45#include <linux/filter.h>
46#include <linux/audit.h>
47#include <sys/ptrace.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030048#include <linux/random.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030049
Ingo Molnar456857b2013-09-12 15:29:00 +020050/* For older distros: */
51#ifndef MAP_STACK
52# define MAP_STACK 0x20000
53#endif
54
55#ifndef MADV_HWPOISON
56# define MADV_HWPOISON 100
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -030057
Ingo Molnar456857b2013-09-12 15:29:00 +020058#endif
59
60#ifndef MADV_MERGEABLE
61# define MADV_MERGEABLE 12
62#endif
63
64#ifndef MADV_UNMERGEABLE
65# define MADV_UNMERGEABLE 13
66#endif
67
Ben Hutchings79d26a62014-02-06 01:00:35 +000068#ifndef EFD_SEMAPHORE
69# define EFD_SEMAPHORE 1
70#endif
71
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030072#ifndef EFD_NONBLOCK
73# define EFD_NONBLOCK 00004000
74#endif
75
76#ifndef EFD_CLOEXEC
77# define EFD_CLOEXEC 02000000
78#endif
79
80#ifndef O_CLOEXEC
81# define O_CLOEXEC 02000000
82#endif
83
84#ifndef SOCK_DCCP
85# define SOCK_DCCP 6
86#endif
87
88#ifndef SOCK_CLOEXEC
89# define SOCK_CLOEXEC 02000000
90#endif
91
92#ifndef SOCK_NONBLOCK
93# define SOCK_NONBLOCK 00004000
94#endif
95
96#ifndef MSG_CMSG_CLOEXEC
97# define MSG_CMSG_CLOEXEC 0x40000000
98#endif
99
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300100#ifndef PERF_FLAG_FD_NO_GROUP
101# define PERF_FLAG_FD_NO_GROUP (1UL << 0)
102#endif
103
104#ifndef PERF_FLAG_FD_OUTPUT
105# define PERF_FLAG_FD_OUTPUT (1UL << 1)
106#endif
107
108#ifndef PERF_FLAG_PID_CGROUP
109# define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */
110#endif
111
112#ifndef PERF_FLAG_FD_CLOEXEC
113# define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */
114#endif
115
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300116struct trace {
117 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300118 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300119 struct {
120 int max;
121 struct syscall *table;
122 struct {
123 struct perf_evsel *sys_enter,
124 *sys_exit;
125 } events;
126 } syscalls;
127 struct record_opts opts;
128 struct perf_evlist *evlist;
129 struct machine *host;
130 struct thread *current;
131 u64 base_time;
132 FILE *output;
133 unsigned long nr_events;
134 struct strlist *ev_qualifier;
135 struct {
136 size_t nr;
137 int *entries;
138 } ev_qualifier_ids;
139 struct intlist *tid_list;
140 struct intlist *pid_list;
141 struct {
142 size_t nr;
143 pid_t *entries;
144 } filter_pids;
145 double duration_filter;
146 double runtime_ms;
147 struct {
148 u64 vfs_getname,
149 proc_getname;
150 } stats;
151 bool not_ev_qualifier;
152 bool live;
153 bool full_time;
154 bool sched;
155 bool multiple_threads;
156 bool summary;
157 bool summary_only;
158 bool show_comm;
159 bool show_tool_stats;
160 bool trace_syscalls;
161 bool force;
162 bool vfs_getname;
163 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300164 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300165};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300166
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300167struct tp_field {
168 int offset;
169 union {
170 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
171 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
172 };
173};
174
175#define TP_UINT_FIELD(bits) \
176static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
177{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500178 u##bits value; \
179 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
180 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300181}
182
183TP_UINT_FIELD(8);
184TP_UINT_FIELD(16);
185TP_UINT_FIELD(32);
186TP_UINT_FIELD(64);
187
188#define TP_UINT_FIELD__SWAPPED(bits) \
189static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
190{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500191 u##bits value; \
192 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300193 return bswap_##bits(value);\
194}
195
196TP_UINT_FIELD__SWAPPED(16);
197TP_UINT_FIELD__SWAPPED(32);
198TP_UINT_FIELD__SWAPPED(64);
199
200static int tp_field__init_uint(struct tp_field *field,
201 struct format_field *format_field,
202 bool needs_swap)
203{
204 field->offset = format_field->offset;
205
206 switch (format_field->size) {
207 case 1:
208 field->integer = tp_field__u8;
209 break;
210 case 2:
211 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
212 break;
213 case 4:
214 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
215 break;
216 case 8:
217 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
218 break;
219 default:
220 return -1;
221 }
222
223 return 0;
224}
225
226static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
227{
228 return sample->raw_data + field->offset;
229}
230
231static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
232{
233 field->offset = format_field->offset;
234 field->pointer = tp_field__ptr;
235 return 0;
236}
237
238struct syscall_tp {
239 struct tp_field id;
240 union {
241 struct tp_field args, ret;
242 };
243};
244
245static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
246 struct tp_field *field,
247 const char *name)
248{
249 struct format_field *format_field = perf_evsel__field(evsel, name);
250
251 if (format_field == NULL)
252 return -1;
253
254 return tp_field__init_uint(field, format_field, evsel->needs_swap);
255}
256
257#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
258 ({ struct syscall_tp *sc = evsel->priv;\
259 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
260
261static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
262 struct tp_field *field,
263 const char *name)
264{
265 struct format_field *format_field = perf_evsel__field(evsel, name);
266
267 if (format_field == NULL)
268 return -1;
269
270 return tp_field__init_ptr(field, format_field);
271}
272
273#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
274 ({ struct syscall_tp *sc = evsel->priv;\
275 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
276
277static void perf_evsel__delete_priv(struct perf_evsel *evsel)
278{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300279 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300280 perf_evsel__delete(evsel);
281}
282
Namhyung Kim96695d42013-11-12 08:51:45 -0300283static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
284{
285 evsel->priv = malloc(sizeof(struct syscall_tp));
286 if (evsel->priv != NULL) {
287 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
288 goto out_delete;
289
290 evsel->handler = handler;
291 return 0;
292 }
293
294 return -ENOMEM;
295
296out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300297 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300298 return -ENOENT;
299}
300
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300301static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300302{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300303 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300304
David Ahern9aca7f12013-12-04 19:41:39 -0700305 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200306 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700307 evsel = perf_evsel__newtp("syscalls", direction);
308
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200309 if (IS_ERR(evsel))
310 return NULL;
311
312 if (perf_evsel__init_syscall_tp(evsel, handler))
313 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300314
315 return evsel;
316
317out_delete:
318 perf_evsel__delete_priv(evsel);
319 return NULL;
320}
321
322#define perf_evsel__sc_tp_uint(evsel, name, sample) \
323 ({ struct syscall_tp *fields = evsel->priv; \
324 fields->name.integer(&fields->name, sample); })
325
326#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
327 ({ struct syscall_tp *fields = evsel->priv; \
328 fields->name.pointer(&fields->name, sample); })
329
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300330struct syscall_arg {
331 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300332 struct thread *thread;
333 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300334 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300335 u8 idx;
336 u8 mask;
337};
338
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300339struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300340 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300341 int nr_entries;
342 const char **entries;
343};
344
345#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
346 .nr_entries = ARRAY_SIZE(array), \
347 .entries = array, \
348}
349
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300350#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
351 .offset = off, \
352 .nr_entries = ARRAY_SIZE(array), \
353 .entries = array, \
354}
355
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300356static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
357 const char *intfmt,
358 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300359{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300360 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300361 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300362
363 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300364 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300365
366 return scnprintf(bf, size, "%s", sa->entries[idx]);
367}
368
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300369static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
370 struct syscall_arg *arg)
371{
372 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
373}
374
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300375#define SCA_STRARRAY syscall_arg__scnprintf_strarray
376
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300377#if defined(__i386__) || defined(__x86_64__)
378/*
379 * FIXME: Make this available to all arches as soon as the ioctl beautifier
380 * gets rewritten to support all arches.
381 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300382static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
383 struct syscall_arg *arg)
384{
385 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
386}
387
388#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300389#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300390
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300391static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
392 struct syscall_arg *arg);
393
394#define SCA_FD syscall_arg__scnprintf_fd
395
396static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
397 struct syscall_arg *arg)
398{
399 int fd = arg->val;
400
401 if (fd == AT_FDCWD)
402 return scnprintf(bf, size, "CWD");
403
404 return syscall_arg__scnprintf_fd(bf, size, arg);
405}
406
407#define SCA_FDAT syscall_arg__scnprintf_fd_at
408
409static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
410 struct syscall_arg *arg);
411
412#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
413
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300414static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300415 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300416{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300417 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300418}
419
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300420#define SCA_HEX syscall_arg__scnprintf_hex
421
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300422static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
423 struct syscall_arg *arg)
424{
425 return scnprintf(bf, size, "%d", arg->val);
426}
427
428#define SCA_INT syscall_arg__scnprintf_int
429
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300430static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300431 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300432{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300433 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300434
435 if (prot == PROT_NONE)
436 return scnprintf(bf, size, "NONE");
437#define P_MMAP_PROT(n) \
438 if (prot & PROT_##n) { \
439 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
440 prot &= ~PROT_##n; \
441 }
442
443 P_MMAP_PROT(EXEC);
444 P_MMAP_PROT(READ);
445 P_MMAP_PROT(WRITE);
446#ifdef PROT_SEM
447 P_MMAP_PROT(SEM);
448#endif
449 P_MMAP_PROT(GROWSDOWN);
450 P_MMAP_PROT(GROWSUP);
451#undef P_MMAP_PROT
452
453 if (prot)
454 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
455
456 return printed;
457}
458
459#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
460
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300461static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300462 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300463{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300464 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300465
466#define P_MMAP_FLAG(n) \
467 if (flags & MAP_##n) { \
468 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
469 flags &= ~MAP_##n; \
470 }
471
472 P_MMAP_FLAG(SHARED);
473 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400474#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300475 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400476#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300477 P_MMAP_FLAG(ANONYMOUS);
478 P_MMAP_FLAG(DENYWRITE);
479 P_MMAP_FLAG(EXECUTABLE);
480 P_MMAP_FLAG(FILE);
481 P_MMAP_FLAG(FIXED);
482 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600483#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300484 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600485#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300486 P_MMAP_FLAG(LOCKED);
487 P_MMAP_FLAG(NONBLOCK);
488 P_MMAP_FLAG(NORESERVE);
489 P_MMAP_FLAG(POPULATE);
490 P_MMAP_FLAG(STACK);
491#ifdef MAP_UNINITIALIZED
492 P_MMAP_FLAG(UNINITIALIZED);
493#endif
494#undef P_MMAP_FLAG
495
496 if (flags)
497 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
498
499 return printed;
500}
501
502#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
503
Alex Snast86998dd2014-08-13 18:42:40 +0300504static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
505 struct syscall_arg *arg)
506{
507 int printed = 0, flags = arg->val;
508
509#define P_MREMAP_FLAG(n) \
510 if (flags & MREMAP_##n) { \
511 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
512 flags &= ~MREMAP_##n; \
513 }
514
515 P_MREMAP_FLAG(MAYMOVE);
516#ifdef MREMAP_FIXED
517 P_MREMAP_FLAG(FIXED);
518#endif
519#undef P_MREMAP_FLAG
520
521 if (flags)
522 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
523
524 return printed;
525}
526
527#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
528
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300529static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300530 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300531{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300532 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300533
534 switch (behavior) {
535#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
536 P_MADV_BHV(NORMAL);
537 P_MADV_BHV(RANDOM);
538 P_MADV_BHV(SEQUENTIAL);
539 P_MADV_BHV(WILLNEED);
540 P_MADV_BHV(DONTNEED);
541 P_MADV_BHV(REMOVE);
542 P_MADV_BHV(DONTFORK);
543 P_MADV_BHV(DOFORK);
544 P_MADV_BHV(HWPOISON);
545#ifdef MADV_SOFT_OFFLINE
546 P_MADV_BHV(SOFT_OFFLINE);
547#endif
548 P_MADV_BHV(MERGEABLE);
549 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600550#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300551 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600552#endif
553#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300554 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600555#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300556#ifdef MADV_DONTDUMP
557 P_MADV_BHV(DONTDUMP);
558#endif
559#ifdef MADV_DODUMP
560 P_MADV_BHV(DODUMP);
561#endif
562#undef P_MADV_PHV
563 default: break;
564 }
565
566 return scnprintf(bf, size, "%#x", behavior);
567}
568
569#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
570
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300571static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
572 struct syscall_arg *arg)
573{
574 int printed = 0, op = arg->val;
575
576 if (op == 0)
577 return scnprintf(bf, size, "NONE");
578#define P_CMD(cmd) \
579 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
580 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
581 op &= ~LOCK_##cmd; \
582 }
583
584 P_CMD(SH);
585 P_CMD(EX);
586 P_CMD(NB);
587 P_CMD(UN);
588 P_CMD(MAND);
589 P_CMD(RW);
590 P_CMD(READ);
591 P_CMD(WRITE);
592#undef P_OP
593
594 if (op)
595 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
596
597 return printed;
598}
599
600#define SCA_FLOCK syscall_arg__scnprintf_flock
601
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300602static 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 -0300603{
604 enum syscall_futex_args {
605 SCF_UADDR = (1 << 0),
606 SCF_OP = (1 << 1),
607 SCF_VAL = (1 << 2),
608 SCF_TIMEOUT = (1 << 3),
609 SCF_UADDR2 = (1 << 4),
610 SCF_VAL3 = (1 << 5),
611 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300612 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300613 int cmd = op & FUTEX_CMD_MASK;
614 size_t printed = 0;
615
616 switch (cmd) {
617#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300618 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
619 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
620 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
621 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
622 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
623 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300624 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300625 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
626 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
627 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
628 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
629 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300630 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
631 default: printed = scnprintf(bf, size, "%#x", cmd); break;
632 }
633
634 if (op & FUTEX_PRIVATE_FLAG)
635 printed += scnprintf(bf + printed, size - printed, "|PRIV");
636
637 if (op & FUTEX_CLOCK_REALTIME)
638 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
639
640 return printed;
641}
642
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300643#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
644
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300645static const char *bpf_cmd[] = {
646 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
647 "MAP_GET_NEXT_KEY", "PROG_LOAD",
648};
649static DEFINE_STRARRAY(bpf_cmd);
650
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300651static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
652static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300653
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300654static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
655static DEFINE_STRARRAY(itimers);
656
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300657static const char *keyctl_options[] = {
658 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
659 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
660 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
661 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
662 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
663};
664static DEFINE_STRARRAY(keyctl_options);
665
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300666static const char *whences[] = { "SET", "CUR", "END",
667#ifdef SEEK_DATA
668"DATA",
669#endif
670#ifdef SEEK_HOLE
671"HOLE",
672#endif
673};
674static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300675
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300676static const char *fcntl_cmds[] = {
677 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
678 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
679 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
680 "F_GETOWNER_UIDS",
681};
682static DEFINE_STRARRAY(fcntl_cmds);
683
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300684static const char *rlimit_resources[] = {
685 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
686 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
687 "RTTIME",
688};
689static DEFINE_STRARRAY(rlimit_resources);
690
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300691static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
692static DEFINE_STRARRAY(sighow);
693
David Ahern4f8c1b72013-09-22 19:45:00 -0600694static const char *clockid[] = {
695 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300696 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
697 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600698};
699static DEFINE_STRARRAY(clockid);
700
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300701static const char *socket_families[] = {
702 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
703 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
704 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
705 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
706 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
707 "ALG", "NFC", "VSOCK",
708};
709static DEFINE_STRARRAY(socket_families);
710
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300711#ifndef SOCK_TYPE_MASK
712#define SOCK_TYPE_MASK 0xf
713#endif
714
715static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
716 struct syscall_arg *arg)
717{
718 size_t printed;
719 int type = arg->val,
720 flags = type & ~SOCK_TYPE_MASK;
721
722 type &= SOCK_TYPE_MASK;
723 /*
724 * Can't use a strarray, MIPS may override for ABI reasons.
725 */
726 switch (type) {
727#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
728 P_SK_TYPE(STREAM);
729 P_SK_TYPE(DGRAM);
730 P_SK_TYPE(RAW);
731 P_SK_TYPE(RDM);
732 P_SK_TYPE(SEQPACKET);
733 P_SK_TYPE(DCCP);
734 P_SK_TYPE(PACKET);
735#undef P_SK_TYPE
736 default:
737 printed = scnprintf(bf, size, "%#x", type);
738 }
739
740#define P_SK_FLAG(n) \
741 if (flags & SOCK_##n) { \
742 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
743 flags &= ~SOCK_##n; \
744 }
745
746 P_SK_FLAG(CLOEXEC);
747 P_SK_FLAG(NONBLOCK);
748#undef P_SK_FLAG
749
750 if (flags)
751 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
752
753 return printed;
754}
755
756#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
757
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300758#ifndef MSG_PROBE
759#define MSG_PROBE 0x10
760#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600761#ifndef MSG_WAITFORONE
762#define MSG_WAITFORONE 0x10000
763#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300764#ifndef MSG_SENDPAGE_NOTLAST
765#define MSG_SENDPAGE_NOTLAST 0x20000
766#endif
767#ifndef MSG_FASTOPEN
768#define MSG_FASTOPEN 0x20000000
769#endif
770
771static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
772 struct syscall_arg *arg)
773{
774 int printed = 0, flags = arg->val;
775
776 if (flags == 0)
777 return scnprintf(bf, size, "NONE");
778#define P_MSG_FLAG(n) \
779 if (flags & MSG_##n) { \
780 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
781 flags &= ~MSG_##n; \
782 }
783
784 P_MSG_FLAG(OOB);
785 P_MSG_FLAG(PEEK);
786 P_MSG_FLAG(DONTROUTE);
787 P_MSG_FLAG(TRYHARD);
788 P_MSG_FLAG(CTRUNC);
789 P_MSG_FLAG(PROBE);
790 P_MSG_FLAG(TRUNC);
791 P_MSG_FLAG(DONTWAIT);
792 P_MSG_FLAG(EOR);
793 P_MSG_FLAG(WAITALL);
794 P_MSG_FLAG(FIN);
795 P_MSG_FLAG(SYN);
796 P_MSG_FLAG(CONFIRM);
797 P_MSG_FLAG(RST);
798 P_MSG_FLAG(ERRQUEUE);
799 P_MSG_FLAG(NOSIGNAL);
800 P_MSG_FLAG(MORE);
801 P_MSG_FLAG(WAITFORONE);
802 P_MSG_FLAG(SENDPAGE_NOTLAST);
803 P_MSG_FLAG(FASTOPEN);
804 P_MSG_FLAG(CMSG_CLOEXEC);
805#undef P_MSG_FLAG
806
807 if (flags)
808 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
809
810 return printed;
811}
812
813#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
814
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300815static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
816 struct syscall_arg *arg)
817{
818 size_t printed = 0;
819 int mode = arg->val;
820
821 if (mode == F_OK) /* 0 */
822 return scnprintf(bf, size, "F");
823#define P_MODE(n) \
824 if (mode & n##_OK) { \
825 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
826 mode &= ~n##_OK; \
827 }
828
829 P_MODE(R);
830 P_MODE(W);
831 P_MODE(X);
832#undef P_MODE
833
834 if (mode)
835 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
836
837 return printed;
838}
839
840#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
841
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300842static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
843 struct syscall_arg *arg);
844
845#define SCA_FILENAME syscall_arg__scnprintf_filename
846
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300847static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300848 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300849{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300850 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300851
852 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300853 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300854
855 if (flags == 0)
856 return scnprintf(bf, size, "RDONLY");
857#define P_FLAG(n) \
858 if (flags & O_##n) { \
859 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
860 flags &= ~O_##n; \
861 }
862
863 P_FLAG(APPEND);
864 P_FLAG(ASYNC);
865 P_FLAG(CLOEXEC);
866 P_FLAG(CREAT);
867 P_FLAG(DIRECT);
868 P_FLAG(DIRECTORY);
869 P_FLAG(EXCL);
870 P_FLAG(LARGEFILE);
871 P_FLAG(NOATIME);
872 P_FLAG(NOCTTY);
873#ifdef O_NONBLOCK
874 P_FLAG(NONBLOCK);
875#elif O_NDELAY
876 P_FLAG(NDELAY);
877#endif
878#ifdef O_PATH
879 P_FLAG(PATH);
880#endif
881 P_FLAG(RDWR);
882#ifdef O_DSYNC
883 if ((flags & O_SYNC) == O_SYNC)
884 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
885 else {
886 P_FLAG(DSYNC);
887 }
888#else
889 P_FLAG(SYNC);
890#endif
891 P_FLAG(TRUNC);
892 P_FLAG(WRONLY);
893#undef P_FLAG
894
895 if (flags)
896 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
897
898 return printed;
899}
900
901#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
902
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300903static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size,
904 struct syscall_arg *arg)
905{
906 int printed = 0, flags = arg->val;
907
908 if (flags == 0)
909 return 0;
910
911#define P_FLAG(n) \
912 if (flags & PERF_FLAG_##n) { \
913 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
914 flags &= ~PERF_FLAG_##n; \
915 }
916
917 P_FLAG(FD_NO_GROUP);
918 P_FLAG(FD_OUTPUT);
919 P_FLAG(PID_CGROUP);
920 P_FLAG(FD_CLOEXEC);
921#undef P_FLAG
922
923 if (flags)
924 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
925
926 return printed;
927}
928
929#define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags
930
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300931static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
932 struct syscall_arg *arg)
933{
934 int printed = 0, flags = arg->val;
935
936 if (flags == 0)
937 return scnprintf(bf, size, "NONE");
938#define P_FLAG(n) \
939 if (flags & EFD_##n) { \
940 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
941 flags &= ~EFD_##n; \
942 }
943
944 P_FLAG(SEMAPHORE);
945 P_FLAG(CLOEXEC);
946 P_FLAG(NONBLOCK);
947#undef P_FLAG
948
949 if (flags)
950 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
951
952 return printed;
953}
954
955#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
956
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300957static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
958 struct syscall_arg *arg)
959{
960 int printed = 0, flags = arg->val;
961
962#define P_FLAG(n) \
963 if (flags & O_##n) { \
964 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
965 flags &= ~O_##n; \
966 }
967
968 P_FLAG(CLOEXEC);
969 P_FLAG(NONBLOCK);
970#undef P_FLAG
971
972 if (flags)
973 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
974
975 return printed;
976}
977
978#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
979
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300980static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
981{
982 int sig = arg->val;
983
984 switch (sig) {
985#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
986 P_SIGNUM(HUP);
987 P_SIGNUM(INT);
988 P_SIGNUM(QUIT);
989 P_SIGNUM(ILL);
990 P_SIGNUM(TRAP);
991 P_SIGNUM(ABRT);
992 P_SIGNUM(BUS);
993 P_SIGNUM(FPE);
994 P_SIGNUM(KILL);
995 P_SIGNUM(USR1);
996 P_SIGNUM(SEGV);
997 P_SIGNUM(USR2);
998 P_SIGNUM(PIPE);
999 P_SIGNUM(ALRM);
1000 P_SIGNUM(TERM);
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001001 P_SIGNUM(CHLD);
1002 P_SIGNUM(CONT);
1003 P_SIGNUM(STOP);
1004 P_SIGNUM(TSTP);
1005 P_SIGNUM(TTIN);
1006 P_SIGNUM(TTOU);
1007 P_SIGNUM(URG);
1008 P_SIGNUM(XCPU);
1009 P_SIGNUM(XFSZ);
1010 P_SIGNUM(VTALRM);
1011 P_SIGNUM(PROF);
1012 P_SIGNUM(WINCH);
1013 P_SIGNUM(IO);
1014 P_SIGNUM(PWR);
1015 P_SIGNUM(SYS);
Ben Hutchings02c5bb42014-02-06 01:00:41 +00001016#ifdef SIGEMT
1017 P_SIGNUM(EMT);
1018#endif
1019#ifdef SIGSTKFLT
1020 P_SIGNUM(STKFLT);
1021#endif
1022#ifdef SIGSWI
1023 P_SIGNUM(SWI);
1024#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001025 default: break;
1026 }
1027
1028 return scnprintf(bf, size, "%#x", sig);
1029}
1030
1031#define SCA_SIGNUM syscall_arg__scnprintf_signum
1032
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001033#if defined(__i386__) || defined(__x86_64__)
1034/*
1035 * FIXME: Make this available to all arches.
1036 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001037#define TCGETS 0x5401
1038
1039static const char *tioctls[] = {
1040 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
1041 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
1042 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
1043 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
1044 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
1045 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
1046 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
1047 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
1048 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
1049 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
1050 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
1051 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
1052 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
1053 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
1054 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
1055};
1056
1057static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001058#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001059
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001060static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg)
1061{
1062 int op = arg->val;
1063 size_t printed = 0;
1064
1065 switch (op) {
1066#define P_SECCOMP_SET_MODE_OP(n) case SECCOMP_SET_MODE_##n: printed = scnprintf(bf, size, #n); break
1067 P_SECCOMP_SET_MODE_OP(STRICT);
1068 P_SECCOMP_SET_MODE_OP(FILTER);
1069#undef P_SECCOMP_SET_MODE_OP
1070 default: printed = scnprintf(bf, size, "%#x", op); break;
1071 }
1072
1073 return printed;
1074}
1075
1076#define SCA_SECCOMP_OP syscall_arg__scnprintf_seccomp_op
1077
1078static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size,
1079 struct syscall_arg *arg)
1080{
1081 int printed = 0, flags = arg->val;
1082
1083#define P_FLAG(n) \
1084 if (flags & SECCOMP_FILTER_FLAG_##n) { \
1085 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
1086 flags &= ~SECCOMP_FILTER_FLAG_##n; \
1087 }
1088
1089 P_FLAG(TSYNC);
1090#undef P_FLAG
1091
1092 if (flags)
1093 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
1094
1095 return printed;
1096}
1097
1098#define SCA_SECCOMP_FLAGS syscall_arg__scnprintf_seccomp_flags
1099
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -03001100static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
1101 struct syscall_arg *arg)
1102{
1103 int printed = 0, flags = arg->val;
1104
1105#define P_FLAG(n) \
1106 if (flags & GRND_##n) { \
1107 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
1108 flags &= ~GRND_##n; \
1109 }
1110
1111 P_FLAG(RANDOM);
1112 P_FLAG(NONBLOCK);
1113#undef P_FLAG
1114
1115 if (flags)
1116 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
1117
1118 return printed;
1119}
1120
1121#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
1122
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001123#define STRARRAY(arg, name, array) \
1124 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
1125 .arg_parm = { [arg] = &strarray__##array, }
1126
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001127#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001128#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001129#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001130#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001131
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001132static struct syscall_fmt {
1133 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001134 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001135 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001136 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001137 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001138 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001139 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001140 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001141} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -03001142 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001143 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1144 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001145 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -03001146 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001147 { .name = "brk", .hexret = true,
1148 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001149 { .name = "chdir", .errmsg = true,
1150 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1151 { .name = "chmod", .errmsg = true,
1152 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1153 { .name = "chroot", .errmsg = true,
1154 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -06001155 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001156 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001157 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001158 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -03001159 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001160 { .name = "creat", .errmsg = true,
1161 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001162 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001163 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001164 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001165 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001166 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001167 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001168 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -03001169 { .name = "eventfd2", .errmsg = true,
1170 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001171 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001172 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1173 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001174 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001175 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001176 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001177 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001178 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001179 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001180 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001181 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001182 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001183 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1184 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001185 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001186 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001187 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001188 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1189 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001190 { .name = "fcntl", .errmsg = true,
1191 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1192 [1] = SCA_STRARRAY, /* cmd */ },
1193 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1194 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001195 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -03001196 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001197 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1198 [1] = SCA_FLOCK, /* cmd */ }, },
1199 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001200 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001201 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001202 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001203 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001204 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1205 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001206 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001207 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001208 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001209 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001210 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001211 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -03001212 { .name = "futex", .errmsg = true,
1213 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001214 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001215 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1216 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001217 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001218 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001219 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001220 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001221 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001222 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001223 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001224 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -03001225 { .name = "getrandom", .errmsg = true,
1226 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001227 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001228 { .name = "getxattr", .errmsg = true,
1229 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1230 { .name = "inotify_add_watch", .errmsg = true,
1231 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001232 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001233 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001234#if defined(__i386__) || defined(__x86_64__)
1235/*
1236 * FIXME: Make this available to all arches.
1237 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001238 [1] = SCA_STRHEXARRAY, /* cmd */
1239 [2] = SCA_HEX, /* arg */ },
1240 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001241#else
1242 [2] = SCA_HEX, /* arg */ }, },
1243#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -03001244 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001245 { .name = "kill", .errmsg = true,
1246 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001247 { .name = "lchown", .errmsg = true,
1248 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1249 { .name = "lgetxattr", .errmsg = true,
1250 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001251 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001252 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001253 { .name = "listxattr", .errmsg = true,
1254 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001255 { .name = "llistxattr", .errmsg = true,
1256 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1257 { .name = "lremovexattr", .errmsg = true,
1258 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001259 { .name = "lseek", .errmsg = true,
1260 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1261 [2] = SCA_STRARRAY, /* whence */ },
1262 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001263 { .name = "lsetxattr", .errmsg = true,
1264 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001265 { .name = "lstat", .errmsg = true, .alias = "newlstat",
1266 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001267 { .name = "lsxattr", .errmsg = true,
1268 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001269 { .name = "madvise", .errmsg = true,
1270 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1271 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001272 { .name = "mkdir", .errmsg = true,
1273 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001274 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001275 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1276 [1] = SCA_FILENAME, /* pathname */ }, },
1277 { .name = "mknod", .errmsg = true,
1278 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001279 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001280 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1281 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001282 { .name = "mlock", .errmsg = true,
1283 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1284 { .name = "mlockall", .errmsg = true,
1285 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001286 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001287 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001288 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001289 [3] = SCA_MMAP_FLAGS, /* flags */
1290 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001291 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001292 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1293 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001294 { .name = "mq_unlink", .errmsg = true,
1295 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001296 { .name = "mremap", .hexret = true,
1297 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001298 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001299 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001300 { .name = "munlock", .errmsg = true,
1301 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001302 { .name = "munmap", .errmsg = true,
1303 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001304 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001305 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001306 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001307 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1308 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001309 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001310 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1311 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001312 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001313 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1314 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001315 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001316 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001317 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001318 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001319 { .name = "perf_event_open", .errmsg = true,
1320 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1321 [2] = SCA_INT, /* cpu */
1322 [3] = SCA_FD, /* group_fd */
1323 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001324 { .name = "pipe2", .errmsg = true,
1325 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001326 { .name = "poll", .errmsg = true, .timeout = true, },
1327 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001328 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001329 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001330 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001331 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001332 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001333 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001334 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001335 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001336 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001337 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001338 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001339 { .name = "readlink", .errmsg = true,
1340 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001341 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001342 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1343 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001344 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001345 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001346 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001347 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1348 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001349 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001350 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1351 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001352 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001353 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1354 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001355 { .name = "removexattr", .errmsg = true,
1356 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001357 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001358 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001359 { .name = "rmdir", .errmsg = true,
1360 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001361 { .name = "rt_sigaction", .errmsg = true,
1362 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001363 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001364 { .name = "rt_sigqueueinfo", .errmsg = true,
1365 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1366 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1367 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -03001368 { .name = "sched_setscheduler", .errmsg = true,
1369 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001370 { .name = "seccomp", .errmsg = true,
1371 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
1372 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001373 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001374 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001375 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1376 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001377 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001378 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1379 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001380 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001381 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1382 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -03001383 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001384 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001385 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001386 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001387 { .name = "setxattr", .errmsg = true,
1388 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001389 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001390 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001391 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001392 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1393 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001394 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001395 { .name = "socketpair", .errmsg = true,
1396 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1397 [1] = SCA_SK_TYPE, /* type */ },
1398 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001399 { .name = "stat", .errmsg = true, .alias = "newstat",
1400 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001401 { .name = "statfs", .errmsg = true,
1402 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1403 { .name = "swapoff", .errmsg = true,
1404 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1405 { .name = "swapon", .errmsg = true,
1406 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001407 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001408 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001409 { .name = "tgkill", .errmsg = true,
1410 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1411 { .name = "tkill", .errmsg = true,
1412 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001413 { .name = "truncate", .errmsg = true,
1414 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001415 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001416 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001417 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1418 [1] = SCA_FILENAME, /* pathname */ }, },
1419 { .name = "utime", .errmsg = true,
1420 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001421 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001422 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1423 [1] = SCA_FILENAME, /* filename */ }, },
1424 { .name = "utimes", .errmsg = true,
1425 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001426 { .name = "vmsplice", .errmsg = true,
1427 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001428 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001429 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001430 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -03001431 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001432 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001433 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001434 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001435 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001436};
1437
1438static int syscall_fmt__cmp(const void *name, const void *fmtp)
1439{
1440 const struct syscall_fmt *fmt = fmtp;
1441 return strcmp(name, fmt->name);
1442}
1443
1444static struct syscall_fmt *syscall_fmt__find(const char *name)
1445{
1446 const int nmemb = ARRAY_SIZE(syscall_fmts);
1447 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1448}
1449
1450struct syscall {
1451 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001452 int nr_args;
1453 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001454 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001455 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001456 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001457 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001458 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001459};
1460
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001461static size_t fprintf_duration(unsigned long t, FILE *fp)
1462{
1463 double duration = (double)t / NSEC_PER_MSEC;
1464 size_t printed = fprintf(fp, "(");
1465
1466 if (duration >= 1.0)
1467 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1468 else if (duration >= 0.01)
1469 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1470 else
1471 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001472 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001473}
1474
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001475/**
1476 * filename.ptr: The filename char pointer that will be vfs_getname'd
1477 * filename.entry_str_pos: Where to insert the string translated from
1478 * filename.ptr by the vfs_getname tracepoint/kprobe.
1479 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001480struct thread_trace {
1481 u64 entry_time;
1482 u64 exit_time;
1483 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001484 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001485 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001486 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001487 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001488 struct {
1489 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001490 short int entry_str_pos;
1491 bool pending_open;
1492 unsigned int namelen;
1493 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001494 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001495 struct {
1496 int max;
1497 char **table;
1498 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001499
1500 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001501};
1502
1503static struct thread_trace *thread_trace__new(void)
1504{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001505 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1506
1507 if (ttrace)
1508 ttrace->paths.max = -1;
1509
David Ahernbf2575c2013-10-08 21:26:53 -06001510 ttrace->syscall_stats = intlist__new(NULL);
1511
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001512 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001513}
1514
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001515static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001516{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001517 struct thread_trace *ttrace;
1518
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001519 if (thread == NULL)
1520 goto fail;
1521
Namhyung Kim89dceb22014-10-06 09:46:03 +09001522 if (thread__priv(thread) == NULL)
1523 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001524
Namhyung Kim89dceb22014-10-06 09:46:03 +09001525 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001526 goto fail;
1527
Namhyung Kim89dceb22014-10-06 09:46:03 +09001528 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001529 ++ttrace->nr_events;
1530
1531 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001532fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001533 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001534 "WARNING: not enough memory, dropping samples!\n");
1535 return NULL;
1536}
1537
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001538#define TRACE_PFMAJ (1 << 0)
1539#define TRACE_PFMIN (1 << 1)
1540
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001541static const size_t trace__entry_str_size = 2048;
1542
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001543static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001544{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001545 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001546
1547 if (fd > ttrace->paths.max) {
1548 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1549
1550 if (npath == NULL)
1551 return -1;
1552
1553 if (ttrace->paths.max != -1) {
1554 memset(npath + ttrace->paths.max + 1, 0,
1555 (fd - ttrace->paths.max) * sizeof(char *));
1556 } else {
1557 memset(npath, 0, (fd + 1) * sizeof(char *));
1558 }
1559
1560 ttrace->paths.table = npath;
1561 ttrace->paths.max = fd;
1562 }
1563
1564 ttrace->paths.table[fd] = strdup(pathname);
1565
1566 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1567}
1568
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001569static int thread__read_fd_path(struct thread *thread, int fd)
1570{
1571 char linkname[PATH_MAX], pathname[PATH_MAX];
1572 struct stat st;
1573 int ret;
1574
1575 if (thread->pid_ == thread->tid) {
1576 scnprintf(linkname, sizeof(linkname),
1577 "/proc/%d/fd/%d", thread->pid_, fd);
1578 } else {
1579 scnprintf(linkname, sizeof(linkname),
1580 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1581 }
1582
1583 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1584 return -1;
1585
1586 ret = readlink(linkname, pathname, sizeof(pathname));
1587
1588 if (ret < 0 || ret > st.st_size)
1589 return -1;
1590
1591 pathname[ret] = '\0';
1592 return trace__set_fd_pathname(thread, fd, pathname);
1593}
1594
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001595static const char *thread__fd_path(struct thread *thread, int fd,
1596 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001597{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001598 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001599
1600 if (ttrace == NULL)
1601 return NULL;
1602
1603 if (fd < 0)
1604 return NULL;
1605
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001606 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001607 if (!trace->live)
1608 return NULL;
1609 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001610 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001611 return NULL;
1612 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001613
1614 return ttrace->paths.table[fd];
1615}
1616
1617static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1618 struct syscall_arg *arg)
1619{
1620 int fd = arg->val;
1621 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001622 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001623
1624 if (path)
1625 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1626
1627 return printed;
1628}
1629
1630static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1631 struct syscall_arg *arg)
1632{
1633 int fd = arg->val;
1634 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001635 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001636
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001637 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1638 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001639
1640 return printed;
1641}
1642
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001643static void thread__set_filename_pos(struct thread *thread, const char *bf,
1644 unsigned long ptr)
1645{
1646 struct thread_trace *ttrace = thread__priv(thread);
1647
1648 ttrace->filename.ptr = ptr;
1649 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1650}
1651
1652static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1653 struct syscall_arg *arg)
1654{
1655 unsigned long ptr = arg->val;
1656
1657 if (!arg->trace->vfs_getname)
1658 return scnprintf(bf, size, "%#x", ptr);
1659
1660 thread__set_filename_pos(arg->thread, bf, ptr);
1661 return 0;
1662}
1663
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001664static bool trace__filter_duration(struct trace *trace, double t)
1665{
1666 return t < (trace->duration_filter * NSEC_PER_MSEC);
1667}
1668
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001669static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1670{
1671 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1672
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001673 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001674}
1675
Namhyung Kimf15eb532012-10-05 14:02:16 +09001676static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001677static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001678
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001679static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001680{
1681 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001682 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001683}
1684
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001685static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001686 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001687{
1688 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001689 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001690
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001691 if (trace->multiple_threads) {
1692 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001693 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001694 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001695 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001696
1697 return printed;
1698}
1699
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001700static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001701 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001702{
1703 int ret = 0;
1704
1705 switch (event->header.type) {
1706 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001707 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001708 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001709 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001710 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001711 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001712 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001713 break;
1714 }
1715
1716 return ret;
1717}
1718
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001719static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001720 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001721 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001722 struct machine *machine)
1723{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001724 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001725 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001726}
1727
1728static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1729{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001730 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001731
1732 if (err)
1733 return err;
1734
David Ahern8fb598e2013-09-28 13:13:00 -06001735 trace->host = machine__new_host();
1736 if (trace->host == NULL)
1737 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001738
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001739 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001740 return -errno;
1741
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001742 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001743 evlist->threads, trace__tool_process, false,
1744 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001745 if (err)
1746 symbol__exit();
1747
1748 return err;
1749}
1750
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001751static int syscall__set_arg_fmts(struct syscall *sc)
1752{
1753 struct format_field *field;
1754 int idx = 0;
1755
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001756 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001757 if (sc->arg_scnprintf == NULL)
1758 return -1;
1759
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001760 if (sc->fmt)
1761 sc->arg_parm = sc->fmt->arg_parm;
1762
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001763 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001764 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1765 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1766 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001767 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001768 else if (strcmp(field->type, "pid_t") == 0)
1769 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001770 else if (strcmp(field->type, "umode_t") == 0)
1771 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001772 ++idx;
1773 }
1774
1775 return 0;
1776}
1777
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001778static int trace__read_syscall_info(struct trace *trace, int id)
1779{
1780 char tp_name[128];
1781 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001782 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001783
1784 if (name == NULL)
1785 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001786
1787 if (id > trace->syscalls.max) {
1788 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1789
1790 if (nsyscalls == NULL)
1791 return -1;
1792
1793 if (trace->syscalls.max != -1) {
1794 memset(nsyscalls + trace->syscalls.max + 1, 0,
1795 (id - trace->syscalls.max) * sizeof(*sc));
1796 } else {
1797 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1798 }
1799
1800 trace->syscalls.table = nsyscalls;
1801 trace->syscalls.max = id;
1802 }
1803
1804 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001805 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001806
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001807 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001808
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001809 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001810 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001811
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001812 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001813 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001814 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001815 }
1816
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001817 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001818 return -1;
1819
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001820 sc->args = sc->tp_format->format.fields;
1821 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001822 /*
1823 * We need to check and discard the first variable '__syscall_nr'
1824 * or 'nr' that mean the syscall number. It is needless here.
1825 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1826 */
1827 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001828 sc->args = sc->args->next;
1829 --sc->nr_args;
1830 }
1831
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001832 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1833
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001834 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001835}
1836
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001837static int trace__validate_ev_qualifier(struct trace *trace)
1838{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001839 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001840 struct str_node *pos;
1841
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001842 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1843 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1844 sizeof(trace->ev_qualifier_ids.entries[0]));
1845
1846 if (trace->ev_qualifier_ids.entries == NULL) {
1847 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1848 trace->output);
1849 err = -EINVAL;
1850 goto out;
1851 }
1852
1853 i = 0;
1854
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001855 strlist__for_each(pos, trace->ev_qualifier) {
1856 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001857 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001858
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001859 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001860 if (err == 0) {
1861 fputs("Error:\tInvalid syscall ", trace->output);
1862 err = -EINVAL;
1863 } else {
1864 fputs(", ", trace->output);
1865 }
1866
1867 fputs(sc, trace->output);
1868 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001869
1870 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001871 }
1872
1873 if (err < 0) {
1874 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1875 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001876 zfree(&trace->ev_qualifier_ids.entries);
1877 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001878 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001879out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001880 return err;
1881}
1882
David Ahern55d43bc2015-02-19 15:00:22 -05001883/*
1884 * args is to be interpreted as a series of longs but we need to handle
1885 * 8-byte unaligned accesses. args points to raw_data within the event
1886 * and raw_data is guaranteed to be 8-byte unaligned because it is
1887 * preceded by raw_size which is a u32. So we need to copy args to a temp
1888 * variable to read it. Most notably this avoids extended load instructions
1889 * on unaligned addresses
1890 */
1891
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001892static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001893 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001894 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001895{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001896 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001897 unsigned char *p;
1898 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001899
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001900 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001901 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001902 u8 bit = 1;
1903 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001904 .idx = 0,
1905 .mask = 0,
1906 .trace = trace,
1907 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001908 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001909
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001910 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001911 field = field->next, ++arg.idx, bit <<= 1) {
1912 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001913 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001914
1915 /* special care for unaligned accesses */
1916 p = args + sizeof(unsigned long) * arg.idx;
1917 memcpy(&val, p, sizeof(val));
1918
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001919 /*
1920 * Suppress this argument if its value is zero and
1921 * and we don't have a string associated in an
1922 * strarray for it.
1923 */
David Ahern55d43bc2015-02-19 15:00:22 -05001924 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001925 !(sc->arg_scnprintf &&
1926 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1927 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001928 continue;
1929
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001930 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001931 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001932 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001933 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001934 if (sc->arg_parm)
1935 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001936 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1937 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001938 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001939 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001940 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001941 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001942 }
1943 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001944 int i = 0;
1945
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001946 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001947 /* special care for unaligned accesses */
1948 p = args + sizeof(unsigned long) * i;
1949 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001950 printed += scnprintf(bf + printed, size - printed,
1951 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001952 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001953 ++i;
1954 }
1955 }
1956
1957 return printed;
1958}
1959
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001960typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001961 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001962 struct perf_sample *sample);
1963
1964static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001965 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001966{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001967
1968 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001969
1970 /*
1971 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1972 * before that, leaving at a higher verbosity level till that is
1973 * explained. Reproduced with plain ftrace with:
1974 *
1975 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1976 * grep "NR -1 " /t/trace_pipe
1977 *
1978 * After generating some load on the machine.
1979 */
1980 if (verbose > 1) {
1981 static u64 n;
1982 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1983 id, perf_evsel__name(evsel), ++n);
1984 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001985 return NULL;
1986 }
1987
1988 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1989 trace__read_syscall_info(trace, id))
1990 goto out_cant_read;
1991
1992 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1993 goto out_cant_read;
1994
1995 return &trace->syscalls.table[id];
1996
1997out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001998 if (verbose) {
1999 fprintf(trace->output, "Problems reading syscall %d", id);
2000 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
2001 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
2002 fputs(" information\n", trace->output);
2003 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002004 return NULL;
2005}
2006
David Ahernbf2575c2013-10-08 21:26:53 -06002007static void thread__update_stats(struct thread_trace *ttrace,
2008 int id, struct perf_sample *sample)
2009{
2010 struct int_node *inode;
2011 struct stats *stats;
2012 u64 duration = 0;
2013
2014 inode = intlist__findnew(ttrace->syscall_stats, id);
2015 if (inode == NULL)
2016 return;
2017
2018 stats = inode->priv;
2019 if (stats == NULL) {
2020 stats = malloc(sizeof(struct stats));
2021 if (stats == NULL)
2022 return;
2023 init_stats(stats);
2024 inode->priv = stats;
2025 }
2026
2027 if (ttrace->entry_time && sample->time > ttrace->entry_time)
2028 duration = sample->time - ttrace->entry_time;
2029
2030 update_stats(stats, duration);
2031}
2032
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03002033static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
2034{
2035 struct thread_trace *ttrace;
2036 u64 duration;
2037 size_t printed;
2038
2039 if (trace->current == NULL)
2040 return 0;
2041
2042 ttrace = thread__priv(trace->current);
2043
2044 if (!ttrace->entry_pending)
2045 return 0;
2046
2047 duration = sample->time - ttrace->entry_time;
2048
2049 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
2050 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
2051 ttrace->entry_pending = false;
2052
2053 return printed;
2054}
2055
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002056static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002057 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002058 struct perf_sample *sample)
2059{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002060 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002061 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002062 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002063 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002064 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002065 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002066 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002067
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002068 if (sc == NULL)
2069 return -1;
2070
David Ahern8fb598e2013-09-28 13:13:00 -06002071 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002072 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002073 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002074 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002075
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002076 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002077
2078 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002079 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002080 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002081 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002082 }
2083
David Ahern13f22a22015-03-19 12:23:03 -06002084 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03002085 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03002086
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002087 ttrace->entry_time = sample->time;
2088 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002089 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002090
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002091 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002092 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002093
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03002094 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07002095 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002096 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
2097 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002098 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002099 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002100 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002101 /* See trace__vfs_getname & trace__sys_exit */
2102 ttrace->filename.pending_open = false;
2103 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002104
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002105 if (trace->current != thread) {
2106 thread__put(trace->current);
2107 trace->current = thread__get(thread);
2108 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002109 err = 0;
2110out_put:
2111 thread__put(thread);
2112 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002113}
2114
2115static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002116 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002117 struct perf_sample *sample)
2118{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002119 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002120 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002121 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002122 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002123 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002124 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002125
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002126 if (sc == NULL)
2127 return -1;
2128
David Ahern8fb598e2013-09-28 13:13:00 -06002129 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002130 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002131 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002132 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002133
David Ahernbf2575c2013-10-08 21:26:53 -06002134 if (trace->summary)
2135 thread__update_stats(ttrace, id, sample);
2136
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002137 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002138
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002139 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002140 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
2141 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002142 ++trace->stats.vfs_getname;
2143 }
2144
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002145 ttrace->exit_time = sample->time;
2146
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002147 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002148 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002149 if (trace__filter_duration(trace, duration))
2150 goto out;
2151 } else if (trace->duration_filter)
2152 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002153
David Ahernfd2eaba2013-11-12 09:31:15 -07002154 if (trace->summary_only)
2155 goto out;
2156
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002157 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002158
2159 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002160 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002161 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002162 fprintf(trace->output, " ... [");
2163 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
2164 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002165 }
2166
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002167 if (sc->fmt == NULL) {
2168signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002169 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03002170 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00002171 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002172 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
2173 *e = audit_errno_to_name(-ret);
2174
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002175 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002176 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002177 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03002178 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002179 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03002180 else if (sc->fmt->errpid) {
2181 struct thread *child = machine__find_thread(trace->host, ret, ret);
2182
2183 if (child != NULL) {
2184 fprintf(trace->output, ") = %ld", ret);
2185 if (child->comm_set)
2186 fprintf(trace->output, " (%s)", thread__comm_str(child));
2187 thread__put(child);
2188 }
2189 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002190 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002191
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002192 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002193out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002194 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002195 err = 0;
2196out_put:
2197 thread__put(thread);
2198 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002199}
2200
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002201static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002202 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002203 struct perf_sample *sample)
2204{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002205 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2206 struct thread_trace *ttrace;
2207 size_t filename_len, entry_str_len, to_move;
2208 ssize_t remaining_space;
2209 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002210 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002211
2212 if (!thread)
2213 goto out;
2214
2215 ttrace = thread__priv(thread);
2216 if (!ttrace)
2217 goto out;
2218
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002219 filename_len = strlen(filename);
2220
2221 if (ttrace->filename.namelen < filename_len) {
2222 char *f = realloc(ttrace->filename.name, filename_len + 1);
2223
2224 if (f == NULL)
2225 goto out;
2226
2227 ttrace->filename.namelen = filename_len;
2228 ttrace->filename.name = f;
2229 }
2230
2231 strcpy(ttrace->filename.name, filename);
2232 ttrace->filename.pending_open = true;
2233
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002234 if (!ttrace->filename.ptr)
2235 goto out;
2236
2237 entry_str_len = strlen(ttrace->entry_str);
2238 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2239 if (remaining_space <= 0)
2240 goto out;
2241
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002242 if (filename_len > (size_t)remaining_space) {
2243 filename += filename_len - remaining_space;
2244 filename_len = remaining_space;
2245 }
2246
2247 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2248 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2249 memmove(pos + filename_len, pos, to_move);
2250 memcpy(pos, filename, filename_len);
2251
2252 ttrace->filename.ptr = 0;
2253 ttrace->filename.entry_str_pos = 0;
2254out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002255 return 0;
2256}
2257
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002258static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002259 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002260 struct perf_sample *sample)
2261{
2262 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2263 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06002264 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03002265 sample->pid,
2266 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002267 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002268
2269 if (ttrace == NULL)
2270 goto out_dump;
2271
2272 ttrace->runtime_ms += runtime_ms;
2273 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002274 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002275 return 0;
2276
2277out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002278 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002279 evsel->name,
2280 perf_evsel__strval(evsel, sample, "comm"),
2281 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2282 runtime,
2283 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002284 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002285 return 0;
2286}
2287
Wang Nan1d6c9402016-02-26 09:31:55 +00002288static void bpf_output__printer(enum binary_printer_ops op,
2289 unsigned int val, void *extra)
2290{
2291 FILE *output = extra;
2292 unsigned char ch = (unsigned char)val;
2293
2294 switch (op) {
2295 case BINARY_PRINT_CHAR_DATA:
2296 fprintf(output, "%c", isprint(ch) ? ch : '.');
2297 break;
2298 case BINARY_PRINT_DATA_BEGIN:
2299 case BINARY_PRINT_LINE_BEGIN:
2300 case BINARY_PRINT_ADDR:
2301 case BINARY_PRINT_NUM_DATA:
2302 case BINARY_PRINT_NUM_PAD:
2303 case BINARY_PRINT_SEP:
2304 case BINARY_PRINT_CHAR_PAD:
2305 case BINARY_PRINT_LINE_END:
2306 case BINARY_PRINT_DATA_END:
2307 default:
2308 break;
2309 }
2310}
2311
2312static void bpf_output__fprintf(struct trace *trace,
2313 struct perf_sample *sample)
2314{
2315 print_binary(sample->raw_data, sample->raw_size, 8,
2316 bpf_output__printer, trace->output);
2317}
2318
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002319static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2320 union perf_event *event __maybe_unused,
2321 struct perf_sample *sample)
2322{
2323 trace__printf_interrupted_entry(trace, sample);
2324 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002325
2326 if (trace->trace_syscalls)
2327 fprintf(trace->output, "( ): ");
2328
2329 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002330
Wang Nan1d6c9402016-02-26 09:31:55 +00002331 if (perf_evsel__is_bpf_output(evsel)) {
2332 bpf_output__fprintf(trace, sample);
2333 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002334 event_format__fprintf(evsel->tp_format, sample->cpu,
2335 sample->raw_data, sample->raw_size,
2336 trace->output);
2337 }
2338
2339 fprintf(trace->output, ")\n");
2340 return 0;
2341}
2342
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002343static void print_location(FILE *f, struct perf_sample *sample,
2344 struct addr_location *al,
2345 bool print_dso, bool print_sym)
2346{
2347
2348 if ((verbose || print_dso) && al->map)
2349 fprintf(f, "%s@", al->map->dso->long_name);
2350
2351 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002352 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002353 al->addr - al->sym->start);
2354 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002355 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002356 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002357 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002358}
2359
2360static int trace__pgfault(struct trace *trace,
2361 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002362 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002363 struct perf_sample *sample)
2364{
2365 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002366 struct addr_location al;
2367 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002368 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002369 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002370
2371 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002372 ttrace = thread__trace(thread, trace->output);
2373 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002374 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002375
2376 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2377 ttrace->pfmaj++;
2378 else
2379 ttrace->pfmin++;
2380
2381 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002382 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002383
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002384 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002385 sample->ip, &al);
2386
2387 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2388
2389 fprintf(trace->output, "%sfault [",
2390 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2391 "maj" : "min");
2392
2393 print_location(trace->output, sample, &al, false, true);
2394
2395 fprintf(trace->output, "] => ");
2396
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002397 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002398 sample->addr, &al);
2399
2400 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002401 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002402 MAP__FUNCTION, sample->addr, &al);
2403
2404 if (al.map)
2405 map_type = 'x';
2406 else
2407 map_type = '?';
2408 }
2409
2410 print_location(trace->output, sample, &al, true, false);
2411
2412 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002413out:
2414 err = 0;
2415out_put:
2416 thread__put(thread);
2417 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002418}
2419
David Ahernbdc89662013-08-28 22:29:53 -06002420static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2421{
2422 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2423 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2424 return false;
2425
2426 if (trace->pid_list || trace->tid_list)
2427 return true;
2428
2429 return false;
2430}
2431
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002432static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002433 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002434 struct perf_sample *sample)
2435{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002436 /*
2437 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2438 * and don't use sample->time unconditionally, we may end up having
2439 * some other event in the future without PERF_SAMPLE_TIME for good
2440 * reason, i.e. we may not be interested in its timestamps, just in
2441 * it taking place, picking some piece of information when it
2442 * appears in our event stream (vfs_getname comes to mind).
2443 */
2444 if (trace->base_time == 0 && !trace->full_time &&
2445 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002446 trace->base_time = sample->time;
2447}
2448
David Ahern6810fc92013-08-28 22:29:52 -06002449static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002450 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002451 struct perf_sample *sample,
2452 struct perf_evsel *evsel,
2453 struct machine *machine __maybe_unused)
2454{
2455 struct trace *trace = container_of(tool, struct trace, tool);
2456 int err = 0;
2457
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002458 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002459
David Ahernbdc89662013-08-28 22:29:53 -06002460 if (skip_sample(trace, sample))
2461 return 0;
2462
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002463 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002464
David Ahern31605652013-12-04 19:41:41 -07002465 if (handler) {
2466 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002467 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002468 }
David Ahern6810fc92013-08-28 22:29:52 -06002469
2470 return err;
2471}
2472
David Ahernbdc89662013-08-28 22:29:53 -06002473static int parse_target_str(struct trace *trace)
2474{
2475 if (trace->opts.target.pid) {
2476 trace->pid_list = intlist__new(trace->opts.target.pid);
2477 if (trace->pid_list == NULL) {
2478 pr_err("Error parsing process id string\n");
2479 return -EINVAL;
2480 }
2481 }
2482
2483 if (trace->opts.target.tid) {
2484 trace->tid_list = intlist__new(trace->opts.target.tid);
2485 if (trace->tid_list == NULL) {
2486 pr_err("Error parsing thread id string\n");
2487 return -EINVAL;
2488 }
2489 }
2490
2491 return 0;
2492}
2493
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002494static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002495{
2496 unsigned int rec_argc, i, j;
2497 const char **rec_argv;
2498 const char * const record_args[] = {
2499 "record",
2500 "-R",
2501 "-m", "1024",
2502 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002503 };
2504
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002505 const char * const sc_args[] = { "-e", };
2506 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2507 const char * const majpf_args[] = { "-e", "major-faults" };
2508 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2509 const char * const minpf_args[] = { "-e", "minor-faults" };
2510 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2511
David Ahern9aca7f12013-12-04 19:41:39 -07002512 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002513 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2514 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002515 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2516
2517 if (rec_argv == NULL)
2518 return -ENOMEM;
2519
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002520 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002521 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002522 rec_argv[j++] = record_args[i];
2523
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002524 if (trace->trace_syscalls) {
2525 for (i = 0; i < sc_args_nr; i++)
2526 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002527
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002528 /* event string may be different for older kernels - e.g., RHEL6 */
2529 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2530 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2531 else if (is_valid_tracepoint("syscalls:sys_enter"))
2532 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2533 else {
2534 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2535 return -1;
2536 }
David Ahern9aca7f12013-12-04 19:41:39 -07002537 }
David Ahern9aca7f12013-12-04 19:41:39 -07002538
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002539 if (trace->trace_pgfaults & TRACE_PFMAJ)
2540 for (i = 0; i < majpf_args_nr; i++)
2541 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002542
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002543 if (trace->trace_pgfaults & TRACE_PFMIN)
2544 for (i = 0; i < minpf_args_nr; i++)
2545 rec_argv[j++] = minpf_args[i];
2546
2547 for (i = 0; i < (unsigned int)argc; i++)
2548 rec_argv[j++] = argv[i];
2549
2550 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002551}
2552
David Ahernbf2575c2013-10-08 21:26:53 -06002553static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2554
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002555static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002556{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002557 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002558
2559 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002560 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002561
2562 if (perf_evsel__field(evsel, "pathname") == NULL) {
2563 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002564 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002565 }
2566
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002567 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002568 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002569 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002570}
2571
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002572static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2573 u64 config)
2574{
2575 struct perf_evsel *evsel;
2576 struct perf_event_attr attr = {
2577 .type = PERF_TYPE_SOFTWARE,
2578 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002579 };
2580
2581 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002582 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002583
2584 event_attr_init(&attr);
2585
2586 evsel = perf_evsel__new(&attr);
2587 if (!evsel)
2588 return -ENOMEM;
2589
2590 evsel->handler = trace__pgfault;
2591 perf_evlist__add(evlist, evsel);
2592
2593 return 0;
2594}
2595
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002596static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2597{
2598 const u32 type = event->header.type;
2599 struct perf_evsel *evsel;
2600
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002601 if (type != PERF_RECORD_SAMPLE) {
2602 trace__process_event(trace, trace->host, event, sample);
2603 return;
2604 }
2605
2606 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2607 if (evsel == NULL) {
2608 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2609 return;
2610 }
2611
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002612 trace__set_base_time(trace, evsel, sample);
2613
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002614 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2615 sample->raw_data == NULL) {
2616 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2617 perf_evsel__name(evsel), sample->tid,
2618 sample->cpu, sample->raw_size);
2619 } else {
2620 tracepoint_handler handler = evsel->handler;
2621 handler(trace, evsel, event, sample);
2622 }
2623}
2624
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002625static int trace__add_syscall_newtp(struct trace *trace)
2626{
2627 int ret = -1;
2628 struct perf_evlist *evlist = trace->evlist;
2629 struct perf_evsel *sys_enter, *sys_exit;
2630
2631 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2632 if (sys_enter == NULL)
2633 goto out;
2634
2635 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2636 goto out_delete_sys_enter;
2637
2638 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2639 if (sys_exit == NULL)
2640 goto out_delete_sys_enter;
2641
2642 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2643 goto out_delete_sys_exit;
2644
2645 perf_evlist__add(evlist, sys_enter);
2646 perf_evlist__add(evlist, sys_exit);
2647
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002648 trace->syscalls.events.sys_enter = sys_enter;
2649 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002650
2651 ret = 0;
2652out:
2653 return ret;
2654
2655out_delete_sys_exit:
2656 perf_evsel__delete_priv(sys_exit);
2657out_delete_sys_enter:
2658 perf_evsel__delete_priv(sys_enter);
2659 goto out;
2660}
2661
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002662static int trace__set_ev_qualifier_filter(struct trace *trace)
2663{
2664 int err = -1;
2665 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2666 trace->ev_qualifier_ids.nr,
2667 trace->ev_qualifier_ids.entries);
2668
2669 if (filter == NULL)
2670 goto out_enomem;
2671
2672 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2673 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2674
2675 free(filter);
2676out:
2677 return err;
2678out_enomem:
2679 errno = ENOMEM;
2680 goto out;
2681}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002682
Namhyung Kimf15eb532012-10-05 14:02:16 +09002683static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002684{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002685 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002686 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002687 int err = -1, i;
2688 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002689 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002690 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002691
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002692 trace->live = true;
2693
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002694 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002695 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002696
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002697 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002698 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002699
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002700 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002701 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002702 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002703 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002704
2705 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2706 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002707 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002708
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002709 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002710 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2711 trace__sched_stat_runtime))
2712 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002713
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002714 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2715 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002716 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002717 goto out_delete_evlist;
2718 }
2719
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002720 err = trace__symbols_init(trace, evlist);
2721 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002722 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002723 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002724 }
2725
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002726 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002727
Namhyung Kimf15eb532012-10-05 14:02:16 +09002728 signal(SIGCHLD, sig_handler);
2729 signal(SIGINT, sig_handler);
2730
2731 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002732 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002733 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002734 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002735 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002736 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002737 }
2738 }
2739
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002740 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002741 if (err < 0)
2742 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002743
Wang Nanba504232016-02-26 09:31:54 +00002744 err = bpf__apply_obj_config();
2745 if (err) {
2746 char errbuf[BUFSIZ];
2747
2748 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2749 pr_err("ERROR: Apply config to BPF failed: %s\n",
2750 errbuf);
2751 goto out_error_open;
2752 }
2753
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002754 /*
2755 * Better not use !target__has_task() here because we need to cover the
2756 * case where no threads were specified in the command line, but a
2757 * workload was, and in that case we will fill in the thread_map when
2758 * we fork the workload in perf_evlist__prepare_workload.
2759 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002760 if (trace->filter_pids.nr > 0)
2761 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002762 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002763 err = perf_evlist__set_filter_pid(evlist, getpid());
2764
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002765 if (err < 0)
2766 goto out_error_mem;
2767
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002768 if (trace->ev_qualifier_ids.nr > 0) {
2769 err = trace__set_ev_qualifier_filter(trace);
2770 if (err < 0)
2771 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002772
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002773 pr_debug("event qualifier tracepoint filter: %s\n",
2774 trace->syscalls.events.sys_exit->filter);
2775 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002776
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002777 err = perf_evlist__apply_filters(evlist, &evsel);
2778 if (err < 0)
2779 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002780
Jiri Olsaf8850372013-11-28 17:57:22 +01002781 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002782 if (err < 0)
2783 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002784
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002785 if (!target__none(&trace->opts.target))
2786 perf_evlist__enable(evlist);
2787
Namhyung Kimf15eb532012-10-05 14:02:16 +09002788 if (forks)
2789 perf_evlist__start_workload(evlist);
2790
Jiri Olsae13798c2015-06-23 00:36:02 +02002791 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002792 evlist->threads->nr > 1 ||
2793 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002794again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002795 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002796
2797 for (i = 0; i < evlist->nr_mmaps; i++) {
2798 union perf_event *event;
2799
2800 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002801 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002802
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002803 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002804
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002805 err = perf_evlist__parse_sample(evlist, event, &sample);
2806 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002807 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002808 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002809 }
2810
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002811 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002812next_event:
2813 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002814
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002815 if (interrupted)
2816 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002817
2818 if (done && !draining) {
2819 perf_evlist__disable(evlist);
2820 draining = true;
2821 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002822 }
2823 }
2824
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002825 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002826 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002827
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002828 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2829 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2830 draining = true;
2831
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002832 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002833 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002834 } else {
2835 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002836 }
2837
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002838out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002839 thread__zput(trace->current);
2840
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002841 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002842
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002843 if (!err) {
2844 if (trace->summary)
2845 trace__fprintf_thread_summary(trace, trace->output);
2846
2847 if (trace->show_tool_stats) {
2848 fprintf(trace->output, "Stats:\n "
2849 " vfs_getname : %" PRIu64 "\n"
2850 " proc_getname: %" PRIu64 "\n",
2851 trace->stats.vfs_getname,
2852 trace->stats.proc_getname);
2853 }
2854 }
David Ahernbf2575c2013-10-08 21:26:53 -06002855
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002856out_delete_evlist:
2857 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002858 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002859 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002860 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002861{
2862 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002863
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002864out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002865 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002866 goto out_error;
2867
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002868out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002869 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002870 goto out_error;
2871
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002872out_error_mmap:
2873 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2874 goto out_error;
2875
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002876out_error_open:
2877 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2878
2879out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002880 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302881 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002882
2883out_error_apply_filters:
2884 fprintf(trace->output,
2885 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2886 evsel->filter, perf_evsel__name(evsel), errno,
2887 strerror_r(errno, errbuf, sizeof(errbuf)));
2888 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002889}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002890out_error_mem:
2891 fprintf(trace->output, "Not enough memory to run!\n");
2892 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002893
2894out_errno:
2895 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2896 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002897}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002898
David Ahern6810fc92013-08-28 22:29:52 -06002899static int trace__replay(struct trace *trace)
2900{
2901 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002902 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002903 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002904 struct perf_data_file file = {
2905 .path = input_name,
2906 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002907 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002908 };
David Ahern6810fc92013-08-28 22:29:52 -06002909 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002910 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002911 int err = -1;
2912
2913 trace->tool.sample = trace__process_sample;
2914 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002915 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002916 trace->tool.comm = perf_event__process_comm;
2917 trace->tool.exit = perf_event__process_exit;
2918 trace->tool.fork = perf_event__process_fork;
2919 trace->tool.attr = perf_event__process_attr;
2920 trace->tool.tracing_data = perf_event__process_tracing_data;
2921 trace->tool.build_id = perf_event__process_build_id;
2922
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002923 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002924 trace->tool.ordering_requires_timestamps = true;
2925
2926 /* add tid to output */
2927 trace->multiple_threads = true;
2928
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002929 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002930 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002931 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002932
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002933 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002934 goto out;
2935
David Ahern8fb598e2013-09-28 13:13:00 -06002936 trace->host = &session->machines.host;
2937
David Ahern6810fc92013-08-28 22:29:52 -06002938 err = perf_session__set_tracepoints_handlers(session, handlers);
2939 if (err)
2940 goto out;
2941
Namhyung Kim003824e2013-11-12 15:25:00 +09002942 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2943 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002944 /* older kernels have syscalls tp versus raw_syscalls */
2945 if (evsel == NULL)
2946 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2947 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002948
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002949 if (evsel &&
2950 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2951 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002952 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2953 goto out;
2954 }
2955
2956 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2957 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002958 if (evsel == NULL)
2959 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2960 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002961 if (evsel &&
2962 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2963 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002964 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002965 goto out;
2966 }
2967
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002968 evlist__for_each(session->evlist, evsel) {
2969 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2970 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2971 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2972 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2973 evsel->handler = trace__pgfault;
2974 }
2975
David Ahernbdc89662013-08-28 22:29:53 -06002976 err = parse_target_str(trace);
2977 if (err != 0)
2978 goto out;
2979
David Ahern6810fc92013-08-28 22:29:52 -06002980 setup_pager();
2981
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002982 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002983 if (err)
2984 pr_err("Failed to process events, error %d", err);
2985
David Ahernbf2575c2013-10-08 21:26:53 -06002986 else if (trace->summary)
2987 trace__fprintf_thread_summary(trace, trace->output);
2988
David Ahern6810fc92013-08-28 22:29:52 -06002989out:
2990 perf_session__delete(session);
2991
2992 return err;
2993}
2994
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002995static size_t trace__fprintf_threads_header(FILE *fp)
2996{
2997 size_t printed;
2998
Pekka Enberg99ff7152013-11-12 16:42:14 +02002999 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06003000
3001 return printed;
3002}
3003
3004static size_t thread__dump_stats(struct thread_trace *ttrace,
3005 struct trace *trace, FILE *fp)
3006{
3007 struct stats *stats;
3008 size_t printed = 0;
3009 struct syscall *sc;
3010 struct int_node *inode = intlist__first(ttrace->syscall_stats);
3011
3012 if (inode == NULL)
3013 return 0;
3014
3015 printed += fprintf(fp, "\n");
3016
Milian Wolff834fd462015-08-06 11:24:29 +02003017 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
3018 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
3019 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02003020
David Ahernbf2575c2013-10-08 21:26:53 -06003021 /* each int_node is a syscall */
3022 while (inode) {
3023 stats = inode->priv;
3024 if (stats) {
3025 double min = (double)(stats->min) / NSEC_PER_MSEC;
3026 double max = (double)(stats->max) / NSEC_PER_MSEC;
3027 double avg = avg_stats(stats);
3028 double pct;
3029 u64 n = (u64) stats->n;
3030
3031 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
3032 avg /= NSEC_PER_MSEC;
3033
3034 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02003035 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02003036 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
3037 n, avg * n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02003038 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06003039 }
3040
3041 inode = intlist__next(inode);
3042 }
3043
3044 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003045
3046 return printed;
3047}
3048
David Ahern896cbb52013-09-28 13:12:59 -06003049/* struct used to pass data to per-thread function */
3050struct summary_data {
3051 FILE *fp;
3052 struct trace *trace;
3053 size_t printed;
3054};
3055
3056static int trace__fprintf_one_thread(struct thread *thread, void *priv)
3057{
3058 struct summary_data *data = priv;
3059 FILE *fp = data->fp;
3060 size_t printed = data->printed;
3061 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09003062 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06003063 double ratio;
3064
3065 if (ttrace == NULL)
3066 return 0;
3067
3068 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
3069
Pekka Enberg15e65c62013-11-14 18:43:30 +02003070 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003071 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02003072 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04003073 if (ttrace->pfmaj)
3074 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
3075 if (ttrace->pfmin)
3076 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003077 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06003078 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06003079
3080 data->printed += printed;
3081
3082 return 0;
3083}
3084
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003085static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
3086{
David Ahern896cbb52013-09-28 13:12:59 -06003087 struct summary_data data = {
3088 .fp = fp,
3089 .trace = trace
3090 };
3091 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003092
David Ahern896cbb52013-09-28 13:12:59 -06003093 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003094
David Ahern896cbb52013-09-28 13:12:59 -06003095 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003096}
3097
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003098static int trace__set_duration(const struct option *opt, const char *str,
3099 int unset __maybe_unused)
3100{
3101 struct trace *trace = opt->value;
3102
3103 trace->duration_filter = atof(str);
3104 return 0;
3105}
3106
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08003107static int trace__set_filter_pids(const struct option *opt, const char *str,
3108 int unset __maybe_unused)
3109{
3110 int ret = -1;
3111 size_t i;
3112 struct trace *trace = opt->value;
3113 /*
3114 * FIXME: introduce a intarray class, plain parse csv and create a
3115 * { int nr, int entries[] } struct...
3116 */
3117 struct intlist *list = intlist__new(str);
3118
3119 if (list == NULL)
3120 return -1;
3121
3122 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
3123 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
3124
3125 if (trace->filter_pids.entries == NULL)
3126 goto out;
3127
3128 trace->filter_pids.entries[0] = getpid();
3129
3130 for (i = 1; i < trace->filter_pids.nr; ++i)
3131 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
3132
3133 intlist__delete(list);
3134 ret = 0;
3135out:
3136 return ret;
3137}
3138
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003139static int trace__open_output(struct trace *trace, const char *filename)
3140{
3141 struct stat st;
3142
3143 if (!stat(filename, &st) && st.st_size) {
3144 char oldname[PATH_MAX];
3145
3146 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
3147 unlink(oldname);
3148 rename(filename, oldname);
3149 }
3150
3151 trace->output = fopen(filename, "w");
3152
3153 return trace->output == NULL ? -errno : 0;
3154}
3155
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003156static int parse_pagefaults(const struct option *opt, const char *str,
3157 int unset __maybe_unused)
3158{
3159 int *trace_pgfaults = opt->value;
3160
3161 if (strcmp(str, "all") == 0)
3162 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
3163 else if (strcmp(str, "maj") == 0)
3164 *trace_pgfaults |= TRACE_PFMAJ;
3165 else if (strcmp(str, "min") == 0)
3166 *trace_pgfaults |= TRACE_PFMIN;
3167 else
3168 return -1;
3169
3170 return 0;
3171}
3172
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003173static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3174{
3175 struct perf_evsel *evsel;
3176
3177 evlist__for_each(evlist, evsel)
3178 evsel->handler = handler;
3179}
3180
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003181int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3182{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003183 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003184 "perf trace [<options>] [<command>]",
3185 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003186 "perf trace record [<options>] [<command>]",
3187 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003188 NULL
3189 };
3190 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003191 .syscalls = {
3192 . max = -1,
3193 },
3194 .opts = {
3195 .target = {
3196 .uid = UINT_MAX,
3197 .uses_mmap = true,
3198 },
3199 .user_freq = UINT_MAX,
3200 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003201 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003202 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003203 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003204 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003205 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003206 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003207 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003208 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003209 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003210 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003211 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003212 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3213 "event selector. use 'perf list' to list available events",
3214 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003215 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3216 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003217 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03003218 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003219 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003220 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003221 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3222 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003223 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003224 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003225 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3226 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003227 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003228 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003229 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003230 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003231 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003232 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003233 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3234 "number of mmap data pages",
3235 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003236 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003237 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003238 OPT_CALLBACK(0, "duration", &trace, "float",
3239 "show only events with duration > N.M ms",
3240 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003241 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003242 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003243 OPT_BOOLEAN('T', "time", &trace.full_time,
3244 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003245 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3246 "Show only syscall summary with statistics"),
3247 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3248 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003249 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3250 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003251 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003252 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003253 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3254 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003255 OPT_END()
3256 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003257 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003258 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003259 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003260
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003261 signal(SIGSEGV, sighandler_dump_stack);
3262 signal(SIGFPE, sighandler_dump_stack);
3263
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003264 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003265 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003266
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003267 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003268 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003269 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003270 goto out;
3271 }
3272
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003273 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3274 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003275
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003276 if (trace.trace_pgfaults) {
3277 trace.opts.sample_address = true;
3278 trace.opts.sample_time = true;
3279 }
3280
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003281 if (trace.evlist->nr_entries > 0)
3282 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3283
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003284 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3285 return trace__record(&trace, argc-1, &argv[1]);
3286
3287 /* summary_only implies summary option, but don't overwrite summary if set */
3288 if (trace.summary_only)
3289 trace.summary = trace.summary_only;
3290
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003291 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3292 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003293 pr_err("Please specify something to trace.\n");
3294 return -1;
3295 }
3296
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003297 if (output_name != NULL) {
3298 err = trace__open_output(&trace, output_name);
3299 if (err < 0) {
3300 perror("failed to create output file");
3301 goto out;
3302 }
3303 }
3304
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003305 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3306
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003307 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003308 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003309 struct strlist_config slist_config = {
3310 .dirname = system_path(STRACE_GROUPS_DIR),
3311 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003312
3313 trace.not_ev_qualifier = *s == '!';
3314 if (trace.not_ev_qualifier)
3315 ++s;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003316 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003317 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003318 fputs("Not enough memory to parse event qualifier",
3319 trace.output);
3320 err = -ENOMEM;
3321 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003322 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003323
3324 err = trace__validate_ev_qualifier(&trace);
3325 if (err)
3326 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003327 }
3328
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003329 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003330 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003331 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003332 fprintf(trace.output, "%s", bf);
3333 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003334 }
3335
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003336 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003337 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003338 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003339 fprintf(trace.output, "%s", bf);
3340 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003341 }
3342
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003343 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003344 trace.opts.target.system_wide = true;
3345
David Ahern6810fc92013-08-28 22:29:52 -06003346 if (input_name)
3347 err = trace__replay(&trace);
3348 else
3349 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003350
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003351out_close:
3352 if (output_name != NULL)
3353 fclose(trace.output);
3354out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003355 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003356}